微服務的程式間通訊(IPC)
本文介紹了幾種典型的微服務間通訊方式,並提供了幾種相應的實現方式。
微服務的程式間通訊架構圖:
術語
IPC:程式間通訊
MSA:微服務架構
概述
服務間通訊包含兩大類:
- 基於同步請求/響應的通訊,如REST,gRPC
- 基於非同步訊息的通訊,如AMQP或STOMP
通訊視角
視角 #1
-
一對一通訊
-
一對多通訊
視角 #2
- 同步通訊
- 非同步通訊
一對一通訊型別
- 請求/響應通訊
- 非同步請求響應
- 單方面通知
一對多通訊型別
- 釋出/訂閱
- 釋出/非同步響應
APIs
服務API是服務端和客戶端之間的合約。
- 理想情況下,首先應該定義服務的介面,然後再實現服務
服務APIs使用版本語法來命名APIs的版本。版本語法包含三個部分:MAJOR.MINOR.PATCH。
訊息格式
IPC的本質是訊息的互動。訊息有兩種格式:文字格式和二進位制格式。
- 文字格式:JSON,XML
- 二進位制格式:Avro,Protobuf和Thrift
在實現時必須注意訊息格式的跨語言協作,因此不推薦使用JavaSerializer。
RPC
遠端呼叫服務的方法,但對呼叫者來說,就像使用本地方法一樣。
流程:
- 客戶端的業務邏輯呼叫RPI代理介面
- RPI代理通過網路呼叫RPI服務,即呼叫服務端的業務邏輯
- 服務端將結果返回給RPI代理,最終由RPI代理返回給客戶端的業務邏輯。
REST
REST是一種理念,而非協議。REST用到了HTTP。
REST的一個主要理念是資源,它代表一個單獨的業務實體,如Movie,Customer等,或一個物件集合。
REST使用HTTP verb來操作資源,如:
POST /movies
: Create a moviePUT /movies
: Update a movieGET /movies
: Get all moviesGET /movies/{movieId}
: Get a movie
gRPC
gRPC是一個基於二進位制的訊息協議,因此必須優先處理API(定義API)。首先使用IDL定義介面,然後編譯生成期望語言的客戶端和服務端stubs。
斷路器
是一個RPI代理,用於在連續傳送的錯誤超過一定閾值時,在一定時間內拒絕呼叫。
常用的斷路器庫如下:
- Netflix Hystrix ( Java )
- Polly ( .Net )
- Hystrix Go (Go lang)
API通訊的健壯性
為了構建同步通訊的健壯性,需要考慮如下模式:
- 網路超時
- 重試
- 斷路器
- 回滾
- 可靠性測試
服務發現
問題
服務A需要通過API呼叫服務B,因此服務A需要知道服務B的地址。
傳統方式
最簡單的方式是靜態配置例項的網路地址,這樣呼叫者可以在配置檔案中指定該地址。
傳統方式的問題
現在,由於在自動擴容、失敗和升級時會動態建立服務例項,併為例項動態分配網路位置,因此引出了服務發現的需求。
服務發現
服務發現的概念非常簡單,最主要的元件是服務登錄檔,儲存了應用服務例項的網路位置。
服務發現的兩種主要實現方式:
- 服務端和客戶端直接與服務登錄檔互動
- 通過部署平臺(如kubernetes)進行互動
服務發現模式:
- 自注冊
- 客戶端發現
- 服務端發現
非同步訊息
基於訊息的應用通常會使用一個訊息代理(broker),作為服務間的中間人。另一種方式是使用無訊息代理架構。
概念
傳送端會向一個channel寫入訊息,接收者會從該channel中讀取訊息。
訊息
訊息包含首部和訊息體。
首部是一個鍵值對集合,此外還包含一個唯一訊息Id(來自傳送端或由訊息基礎設施生成)。
訊息體包含需要傳送的資料。
訊息型別
- 文件
- 目錄
- 事件
Channels
訊息通過channel進行互動。channel有兩種型別:
- 點到點channel
- 釋出訂閱channel
非同步通訊實現
非同步請求響應
釋出訂閱
無訊息代理
- 服務可以直接進行互動
- ZeroMQ就是一個典型的無訊息代理技術
基於訊息代理的通訊
訊息代理是所有訊息流的中間人。
好處
- 傳送端不需要知道消費端的位置
- 在訊息被消費者處理前,訊息代理會對訊息進行快取
典型的開源訊息代理
- ActiveMQ
- RabbitMQ
- Apache Kafka
在選擇訊息代理時需要考慮的因素
- 支援的程式語言
- 支援的訊息標準
- 訊息順序
- 保證訊息的傳送
- 持久化
- 穩定性
- 可擴充套件性
- 延遲
- 產品競爭力