微服務架構的通信設計模式
今天我們來學習一下微服務的通信設計模式,通信是保證服務請求核心要素,選擇合適的一個通信協議對系統來說可以達到事半功倍。
一、RPC調用模式
目前各種微服務通信社區上,很多種支持RPC模式。有同步請求/響應通信機制,例如基于 HTTP 的 REST 或 GraphQL,或 gRPC。或者可以使用異步的、基于消息的通信機制,例如 AMQP(高級消息隊列協議)或 STOMP(簡單/流式面向文本的消息傳遞協議)。此外,還有許多不同的消息格式。這些格式可以是可讀的,例如 JSON 和 XML。他們還可以使用更高效的二進制格式,例如 Avro 或 Protobuf。
1、RPC 選擇因素
在選擇 RPC 機制之前,考慮一下服務與其客戶端之間的交互方式是很有必要的。客戶服務交互有兩個維度。
(1)一對一還是一對多
- 一對一:每個客戶端請求都由一個服務處理。
- 一對多:每個客戶端請求都由多個服務處理。
(2)同步的還是異步的
- 同步:客戶端在等待服務響應時可能會阻塞。
- 異步:客戶端不會阻塞,并且響應(如果有)并不是立即發送。
2、一對一互動
- 同步請求/響應:服務客戶端請求服務并等待響應。服務的緊密耦合是這種交互方式的結果。
- 異步請求/響應:服務客戶端向服務發送請求,服務異步回復。
- 單向通知:客戶端向服務發送請求,但不期待響應。
3、一對多交互
- 異步發布/訂閱:客戶端發布通知消息,由一個或多個訂閱服務使用。
- 異步發布/異步響應:在這種情況下,客戶端發布一條消息,然后等待來自感興趣服務的響應。
4、消息格式
RPC 本質上是一種消息交換。其中一個重要的設計是消息包含數據的格式。消息格式的選擇會影響 RPC 的效率、API 的可用性及其可演化性。
消息格式有兩種主要類型:文本和二進制。
(1)基于文本的消息格式
JSON 和 XML 是最流行的基于文本的格式。
基于文本的消息格式的優點
- 可讀性高,可自我描述。
基于文本的消息格式的缺點
- 消息很冗長。
- 除了它們的值之外,沒有必要的屬性及其他標簽都會包含其中。
- 解析文本性能開銷很大。
(2)二進制消息格式
Thrift、Protocol Buffers (Protobuf) 和 Avro 是最流行的二進制格式。
二進制消息格式的優點
- 元數據很少,因此有效負載很小。
- 比基于文本的消息解析要快。
二進制消息格式的缺點
- 可讀性差,不可自我描述
二、遠程過程調用模式
當客戶端請求服務時,服務會處理請求并發回響應。雖然一些客戶端可能會在等待響應時阻塞,但其他客戶端可能具有反應性、非阻塞架構。
代理接口通常封裝底層通信協議。
有多種通信協議可供選擇,例如 REST、gRPC 和 GraphQL 等。
三、使用同步模式進行通信
1、REST(代表性狀態轉移)
REST 基于資源的概念,它表示單個業務對象。HTTP(超文本傳輸協議)用于實現 REST。REST 使用 HTTP 來操作由 URL 引用的資源。
2、HTTP 調用方式
- GET: GET 方法向特定的資源發出請求。GET方法不應當被用于產生“副作用”的操作中,例如在Web Application中,其中一個原因是GET可能會被網絡蜘蛛等隨意訪問
- HEAD: HEAD 方法向服務器索與GET請求相一致的響應,只不過響應體將不會被返回。這一方法可以在不必傳輸整個響應內容的情況下,就可以獲取包含在響應小消息頭中的元信息。
- POST: POST請求數據被包含在請求體中。POST請求可能會導致新的資源的建立和/或已有資源的修改。
- PUT: PUT 方法用請求有效負載替換目標資源的所有當前表示。
- DELETE: DELETE 方法請求服務器刪除Request-URL所標識的資源
- CONNECT: CONNECT 方法建立由目標資源標識的服務器的隧道。
- OPTIONS: OPTIONS 方法描述了目標資源的通信選項。
- TRACE: TRACE 方法沿到目標資源的路徑執行消息環回測試。
- PATCH: PATCH 方法將部分修改應用于資源。
3、指定 REST API
API 必須使用 IDL(接口定義語言)定義。最流行的 REST IDL 之一是開放 API 規范,它是從Swagger開源項目演變而來的。
4、挑戰一:在單個請求中獲取多個資源
由于 REST API 通常基于業務對象,因此在一個請求中請求多個相關對象是設計 REST API 時的常見難題之一。客戶端必須至少對相關對象發出多次請求。
使用查詢參數,API 可以使客戶端在獲取資源時檢索相關資源。由于這種方法缺乏可擴展性,GraphQL和Netflix Falcor等替代 API 技術變得越來越受歡迎。
5、挑戰二:映射操作到 HTTP 動詞
另一個常見的 REST API 設計問題是將要對業務對象執行的操作映射到 HTTP 請求上。REST API 使用 PUT 來更新,但是有多種方法可以操作訂單,包括取消訂單、修改訂單等。一種解決方案是定義一個子資源,如 /orders/{orderId}/cancel 或 /orders/{orderId}/revise 以更新資源的特定方面或在 URL 查詢參數中指定動詞。但這些解決方案并不是真正的 RESTful。
由于這個問題,REST 的替代品(例如gRPC)越來越受歡迎。
6、REST 的優勢
- 目前很多微服務框架都支持REST,實現起來相對容易
- Postman 等插件可以輕松地在瀏覽器中測試 HTTP API。
- 它支持直接請求/響應通信。
7、REST 的缺點
- 僅支持請求/響應通信。
- 由于要求客戶端和服務器同時在線,可用性降低。
- 客戶端必須使用服務發現來發現服務實例的 URL。
- 在一個請求中獲取多個資源可能具有挑戰性。
- 將多個更新操作映射到 HTTP 動詞可能具有挑戰性。
四、gRPC
由于 HTTP 僅提供一組有限的請求方式,因此設計支持多個更新操作的 REST API 可能具有挑戰性。
谷歌推出的跨語言客戶端和服務器的框架 gRPC 可以解決這個問題。使用基于協議緩沖區的 IDL 定義 gRPC API,這是 Google 用于序列化結構化數據的語言設計機制。是一種同步通信機制。使用 HTTP/2,客戶端和服務器以協議緩沖區格式交換二進制消息。
1、gRPC 的優勢
- 易于設計具有豐富更新操作集的 API 。
- 消息格式緊湊且高效。
- 雙向流使 RPC 和消息傳遞成為可能。
- 它支持以多種語言編寫的客戶端和服務的互操作性。
2、gRPC 的缺點
- JS 客戶端必須做更多的工作來使用基于 gRPC 的 API,而不是基于 REST/JSON 的 API。
五、GraphQL
GraphQL 解決了使用單個請求獲取多個資源的問題。GraphQL 主要用于從客戶端應用程序查詢數據庫。在后端,GraphQL 向 API 指定如何將數據呈現給客戶端。GraphQL 重新定義了開發人員使用 API 的方式,提供更大的靈活性和更快的上線速度;改進了客戶端-服務器交互,使前者能夠進行精確的數據請求,并只獲得他們需要的數據。
GraphQL 服務器為客戶端提供模式:可以請求的數據模型。
1、GraphQL 的優勢
- 客戶端可以準確地從服務器指定他們需要什么,服務器將以可預測的方式反饋該數據。
- API 使用者確切地知道哪些數據可用以及它是什么形式,因為它是強類型的。
2、GraphQL 的缺點
- 無論查詢成功與否,它總是返回一個 HTTP 狀態碼 200。
- 沒有內置緩存支持
- 它比 REST 更復雜
六、使用異步消息傳遞模式進行通信
使用消息傳遞時,服務會異步交換消息。基于消息的應用程序通常使用像 RabbitMQ 這樣的消息代理,充當服務之間的中介。服務客戶端通過向服務發送消息來向服務發出請求。如果期望響應,服務實例將向客戶端發送單獨的消息。由于通信是異步的,客戶端不會等待響應。相反,客戶端是假設不會立即收到響應的。
1、單向通知
異步消息傳遞使實現單向通知變得容易。通常,客戶端向服務擁有的點對點通道發送消息。服務訂閱頻道處理消息。沒有響應被發回。
2、發布/訂閱
發布/訂閱交互樣式內置于消息傳遞中。客戶端將消息發布到由多個訂閱者讀取的發布-訂閱通道。
3、發布/異步響應
結合了發布/訂閱和請求/響應的元素,形成了更高層次的交互風格。客戶端將指定回復通道頭的消息發布到發布-訂閱通道。消費者將包含相關 id 的回復消息寫入回復通道。客戶端利用相關 id 將回復消息與收集響應的請求進行匹配。