1. 程式人生 > 實用技巧 >PHP微服務叢集搭建

PHP微服務叢集搭建

近些年微服務架構大行其道,趁著最近有時間,來搗鼓搗鼓微服務是怎麼一回事。

微服務架構

微服務的概念由 Martin Fowler 於2014年3月提出:

微服務架構是一種架構模式,它提倡將單一應用程式劃分成一組小的服務,服務之間相互協調、互相配合,為使用者提供最終價值。每個服務執行在其獨立的程序中,服務和服務之間採用輕量級的通訊機制相互溝通。每個服務都圍繞著具體的業務進行構建,並且能夠被獨立的部署到生產環境、類生產環境等。另外,應儘量避免統一的、集中的服務管理機制,對具體的一個服務而言,應根據業務上下文,選擇合適的語言、工具對其進行構建。

下圖是一個電商系統的微服務架構圖:

微服務架構與單體應用相比,具有以下優點:

  1. 每個服務都比較簡單,只關注於一個業務功能;
  2. 微服務架構方式是鬆耦合的,每個服務可以獨立測試、部署、升級、釋出;
  3. 每個微服務可由不同團隊獨立開發,可以各自選擇優秀及最合適的不同的程式語言與工具;
  4. 每個服務可以根據需要進行水平擴充套件,提高系統併發能力。

沒有銀彈,微服務架構在帶來諸多優點的同時,也會有如下缺點:

  1. 微服務架構提高了系統的複雜度,增加了運維開銷及成本。如單體應用可能只需部署至一小片應用服務叢集,而微服務架構可能變成需要構建/測試/部署/執行數十個獨立的服務,並可能需要支援多種語言和環境;
  2. 作為一種分散式系統,微服務架構引入了其他若干問題,例如訊息序列化、網路延遲、非同步機制、容錯處理、服務雪崩等;
  3. 服務管理的複雜性,如服務的註冊、發現、降級、熔斷等問題;
  4. 服務與服務之間存在相互呼叫的情況,為排查系統故障帶來巨大挑戰。

可以說,正是傳統應用架構的系統變得日益臃腫,面臨難以維護、擴充套件的問題,同時容器化技術(Docker)的蓬勃發展和 DevOps 思想的日漸成熟,催生了新的架構設計風格 – 微服務架構的出現。

RPC框架

微服務架構中的各個服務通常不在同一個機器上,甚至不會在同一個網路環境裡,因此微服務之間如何呼叫是一個亟待解決的問題,我們通常使用 RPC 協議來解決:

RPC(Remote Procedure Call),即遠端過程呼叫,是一個計算機通訊協議。該協議允許運行於一臺計算機的程式呼叫另一臺計算機的子程式,而程式設計師無需額外地為這個互動作用程式設計。——維基百科

實現了 RPC 協議的框架,可以讓服務方和呼叫方遮蔽各種底層細節,讓呼叫方像呼叫本地函式一樣呼叫遠端的函式(服務)。RPC 框架一般為服務端和客戶端提供了序列化、反序列化、連線池管理、負載均衡、故障轉移、佇列管理、超時管理、非同步管理等職能。在網上找到一個說明 RPC 框架工作原理圖:

目前,根據序列化資料時採用的技術的不同,可分為jsON-RPC 和 gRPC 兩種:

  • jsON-RPC 是一種基於 JSON 格式的輕量級的 RPC 協議標準,可基於 HTTP 協議來傳輸,或直接基於 TCP 協議來傳輸。 JSON-RPC 優點是易於使用和閱讀。
  • gRPC 是一個高效能、通用的開源 RPC 框架,其由 Google 主要面向移動應用開發並基於 HTTP/2 協議標準而設計,基於 ProtoBuf (Protocol Buffers) 序列化協議開發,且支援眾多開發語言。 gRPC 具有低延遲、高效率、高擴充套件性、支援分散式等優點。

Consul

現在有了 RPC 框架,我們就可以只考慮服務與服務之間的業務呼叫而不用考慮底層傳輸細節。此時,如果服務 A 想呼叫服務 B 時,我們可以在服務 A 中配置服務 B 的 IP 地址和埠,然後剩下的傳輸細節就交給 RPC 框架。這在微服務規模很小的情況下是沒有問題的,但是在服務規模很大、而且每個服務不止部署一個例項的情況下會面臨巨大挑戰。比如,服務 B 部署了三個例項,這時候服務 A 想呼叫服務 B 該請求哪個例項的 IP ?假如服務 B 部署的三個例項有兩個都掛掉了,服務 A 可能會依舊去請求掛掉的例項,服務將不可用。將 IP 地址和埠寫成配置檔案顯得很不靈活,微服務架構往往要保證高可用及動態伸縮。

因此,我們需要一個服務註冊與服務發現的工具,能夠動態地變更服務資訊,並且找到可用的服務的 IP 地址和埠。目前市面上服務發現的工具有很多,如 Consul、ZooKeeper 、Etcd、Doozerd 等,本文主要以 Consul 軟體為例。

Consul 是一個支援多資料中心、分散式高可用的服務發現和配置共享的服務軟體,由 HashiCorp 公司用 Go 語言開發, 基於 Mozilla Public License 2.0 的協議進行開源。 Consul 支援健康檢查,並允許 HTTP 、gRPC 和 DNS 協議呼叫 API 儲存鍵值對。

下面是引入服務註冊與服務發現工具後的架構圖:

在這個架構中:

  • 首先 S-B 的例項啟動後將自身的服務資訊(主要是服務所在的 IP 地址和埠號)註冊到 Consul 中。
  • Consul 會對所有註冊的服務做健康檢查,以此來確定哪些服務例項可用哪些不可用。
  • S-A 啟動後就可以通過訪問 Consul 來獲取到所有健康的 S-B 例項的 IP 和埠,並將這些資訊放入自己的記憶體中,S-A 就可用通過這些資訊來呼叫 S-B。
  • S-A 可以通過監聽 Consul 來更新存入記憶體中的 S-B 的服務資訊。比如 S-B-1 掛了,健康檢查機制就會將其標為不可用,這樣的資訊變動就被 S-A 監聽到了,S-A 就更新自己記憶體中 S-B-1 的服務資訊。

可見, Consul 軟體除了服務註冊和服務發現的功能之外,還提供了健康檢查和狀態變更通知的功能。

資源搜尋網站大全 https://www.renrenfan.com.cn 廣州VI設計公司https://www.houdianzi.com

Hyperf

對於 Java 開發者來說,有技術相當成熟的 Dubbo 和 Spring Cloud 微服務框架可供選擇。作為一名phper,我用 Google 查了一下「php+ 微服務」,發現有用的相關內容少之又少 ,沒有什麼實質性的參考價值,無限惆悵。。。幸好,有大神在基於 Swoole 擴充套件的基礎上,實現了高效能、高靈活性的 PHP 協程框架 Hyperf ,並提供了微服務架構的相關元件。

Hyperf 是基於 Swoole 4.3+ 實現的高效能、高靈活性的 PHP 協程框架,內建協程伺服器及大量常用的元件,效能較傳統基於 PHP-FPM 的框架有質的提升,提供超高效能的同時,也保持著極其靈活的可擴充套件性,標準組件均基於 PSR 標準 實現,基於強大的依賴注入設計,保證了絕大部分元件或類都是 可替換 與 可複用 的。

於是,我在學習了微服務架構相關的基礎知識之後,使用 Hyperf 框架構建了一個基於 PHP 的微服務叢集,這是專案原始碼地址:https://github.com/Jochen-z/p...。該專案使用 Dokcer 搭建,docker-compose.yml程式碼如下:

version: "3" 
 
services: 
  consul-server-leader: 
    image: consul:latest 
    container_name: consul-server-leader 
    command: "agent -server -bootstrap -ui -node=consul-server-leader -client=0.0.0.0" 
    environment: 
      - CONSUL_BIND_INTERFACE=eth0 
    ports: 
      - "8500:8500" 
    networks: 
      - microservice 
 
  microservice-1: 
    build: 
      context: . 
    container_name: "microservice-1" 
    command: "php bin/hyperf.php start" 
    depends_on: 
      - "consul-server-leader" 
    volumes: 
      - ./www/microservice-1:/var/www 
    networks: 
      - microservice 
    tty: true 
 
  microservice-2: 
    build: 
      context: . 
    container_name: "microservice-2" 
    command: "php bin/hyperf.php start" 
    depends_on: 
      - "consul-server-leader" 
    volumes: 
      - ./www/microservice-2:/var/www 
    networks: 
      - microservice 
    tty: true 
 
  app: 
    build: 
      context: . 
    container_name: "app" 
    command: "php bin/hyperf.php start" 
    depends_on: 
      - "microservice-1" 
    volumes: 
      - ./www/web:/var/www 
    ports: 
      - "9501:9501" 
    networks: 
      - microservice 
    tty: true 
 
networks: 
  microservice: 
    driver: bridge 
 
volumes: 
  microservice: 
    driver: local 

這裡啟動了一個 Consul 容器 consul-server-leader 作為服務註冊和服務發現的元件,容器 microservice-1 和 microservice-2 分別提供了加法運算和除法運算的服務。容器 app 作為服務呼叫方,配置了 consul-server-leader 容器的 URL,通過訪問 consul-server-leader 獲取 microservice-1 和 microservice-2 服務的 IP 地址和埠,然後 app通過 RPC 協議呼叫加法運算和除法運算的服務獲取結果並返回給使用者。

app 容器為 Web 應用,部署了一個 Hyperf 專案並對外提供 HTTP 服務。例如,在 App\Controller\IndexController 控制器裡有 add 方法:

public function add(AdditionService $addition) 
{ 
  $a = (int)$this->request->input('a', 1); # 接受前端使用者引數 
  $b = (int)$this->request->input('b', 2); 
 
  return [ 
    'a' => $a, 
    'b' => $b, 
    'add' => $addition->add($a, $b) # RPC呼叫 
  ]; 
} 

在 App\JsonRpc\AdditionService 中 add 的實現:

class AdditionService extends AbstractServiceClient 
{ 
    /** 
     * 定義對應服務提供者的服務名稱 
     * @var string 
     */ 
    protected $serviceName = 'AdditionService'; 
 
    /** 
     * 定義對應服務提供者的服務協議 
     * @var string 
     */ 
    protected $protocol = 'jsonrpc-http'; 
 
    public function add(int $a, int $b): int 
    { 
        return $this->__request(__FUNCTION__, compact('a', 'b')); 
    } 
} 

繼承了 AbstractServiceClient 即可建立一個微服務客戶端請求類,Hyperf 在底層幫我們實現了與 Consul 和服務提供者互動的細節,我們只要 AdditionService 類裡的 add 方法即可遠端呼叫 microservice-1 和 microservice-2 提供的服務。

至此,PHP 微服務叢集搭建就完成了!