微服務架構中的通信風格
在微服務架構中,通信是關鍵要素,關于選擇最有效的服務間交互方法的討論也非常廣泛。在這篇介紹性文章中,我們將探討并總結微服務的最佳通信策略,提供關于何時以及如何有效使用每種通信風格的見解。
交互風格
要有效理解服務在微服務架構中如何通信,首先必須熟悉可用的交互風格。每種風格都有其獨特的優點和缺點。深入了解這些細微差別對于在選擇適當的通信機制之前做出明智決策至關重要。這一基礎知識確保所選方法能夠很好地與系統的具體要求和挑戰相契合。
交互風格可以分為兩個維度,第一個維度是交互是 一對一 還是 一對多:
- 一對一 — 每個客戶端請求由一個服務處理。
- 一對多 — 每個請求由多個服務處理。
第二個維度是交互是 同步 還是 異步。
- 同步 — 客戶端期望服務及時響應,甚至可能會阻塞等待。
- 異步 — 客戶端不會阻塞,響應(如果有的話)不一定會立即發送。
下表展示了不同的維度:
通信維度
讓我們簡要討論每一種。
一對一交互:
- 請求/響應 — 服務客戶端向服務發送請求并等待響應。客戶端期望響應及時到達,甚至可能會阻塞等待。這種交互風格通常導致服務之間緊密耦合。
- 異步請求/響應 — 服務客戶端向服務發送請求,服務異步回復。客戶端不會阻塞等待,因為服務可能很長時間不發送響應。
- 單向通知 — 服務客戶端向服務發送請求,但不期望或發送回復。
一對多交互
- 發布/訂閱 — 客戶端發布通知消息,感興趣的服務消費消息。
- 發布/異步響應 — 客戶端發布請求消息,然后等待一段時間,接收感興趣的服務的響應。
請記住,一個服務可以有多種通信方式。
使用同步遠程過程調用模式通信
客戶端向服務發送請求,服務處理請求并發送響應。某些客戶端可能會阻塞等待響應,而其他客戶端可能具有反應式、非阻塞架構。但與使用消息傳遞不同,客戶端假設響應會及時到達。
下圖展示了RPI的工作原理。客戶端的業務邏輯調用由 RPI代理適配器類 實現的 代理接口。RPI代理 向服務發出請求。
請求由 RPI服務器適配器類 處理,該類通過接口調用服務的業務邏輯。然后,它將回復發送回 RPI代理,后者將結果返回給客戶端的業務邏輯。
代理接口 通常封裝了底層通信協議。有很多協議可供選擇,我們重點關注最流行的協議REST和gRPC。
1.REST API
REST的一個關鍵概念是資源,它通常代表一個業務對象(如客戶或產品)或一組業務對象。REST使用HTTP動詞來操作資源,這些資源通過URL引用。例如,GET請求返回資源的表示,通常是XML文檔或JSON對象,盡管也可以使用其他格式(如二進制)。POST請求創建一個新資源,PUT請求更新一個資源。
REST API的挑戰:
- 在單個請求中獲取多個資源REST資源通常關注業務對象,如客戶和訂單,這給一次請求獲取多個相關對象帶來了挑戰。例如,獲取訂單及其關聯的客戶通常需要多次API調用。常見的解決方法是增強API,使客戶端可以在一次調用中獲取相關資源,例如使用帶有“expand”查詢參數的GET請求來指定相關資源。雖然在很多情況下有效,但這種方法可能復雜且耗時,這促使了像GraphQL這樣的替代技術的興起,以實現更簡化的數據檢索。
- 將操作映射到HTTP動詞*REST API設計中的一個顯著挑戰是如何將業務對象上的特定操作分配給正確的HTTP動詞。例如,更新訂單可能涉及各種操作,如取消或修改*,并非所有更新都符合使用HTTP PUT方法的冪等性要求。常見的方法是為不同的更新操作創建子資源,例如使用POST取消(POST /orders/{orderId}/cancel)或修改訂單(POST /orders/{orderId}/revise)。另一種方法是在URL查詢參數中包含操作。然而,這些方法可能并不完全遵循REST原則。這種將操作映射到HTTP動詞的困難促使了gRPC等替代技術的流行。
使用REST有很多優點:
- 簡單且熟悉。
- 可以在瀏覽器中使用插件(例如Postman)或在命令行中使用curl測試HTTP API(假設使用JSON或其他文本格式)。
- 直接支持請求/響應風格的通信。
- HTTP當然是防火墻友好的。?不需要中間代理,簡化了系統架構。
使用REST也有一些缺點:
- 僅支持請求/響應風格的通信。
- 可用性降低。由于客戶端和服務直接通信,沒有中介緩沖消息,它們必須在整個交換期間都在運行。
- 客戶端必須知道服務實例的位置(URL)。在現代應用中,這是一個不小的問題。客戶端必須使用所謂的服務發現機制來定位服務實例。
- 在單個請求中獲取多個資源具有挑戰性。?將多個更新操作映射到HTTP動詞有時很困難。
2.使用gRPC
REST API通常在使用有限的HTTP動詞處理多個更新操作時遇到困難。gRPC通過使用二進制消息協議提供了一個替代方案,強調API優先的方法。它利用谷歌開發的Protocol Buffers(Protobuf),這是一種語言中立的序列化系統,允許開發人員使用基于Protocol Buffers的接口定義語言(IDL)定義API。此設置使得可以使用Protocol Buffer編譯器自動生成各種編程語言(如Java、C#、NodeJS和GoLang)的客戶端和服務器代碼。gRPC API運行在HTTP/2之上,支持簡單的請求/響應和流式RPC,服務器可以向客戶端發送消息流或反之亦然。此技術支持創建具有強類型方法的明確服務接口,為處理微服務架構中的各種復雜通信模式提供了強大的框架。
gRPC有幾個優點:
- 設計具有豐富更新操作的API非常簡單。
- 具有高效、緊湊的IPC機制,特別是在交換大型消息時。
- 雙向流支持RPI和消息傳遞風格的通信。
- 使客戶端和服務在各種編程語言之間的互操作性成為可能。
gRPC也有一些缺點:
- JavaScript客戶端使用gRPC API比使用REST/JSON API工作量更大。
- 較舊的防火墻可能不支持HTTP/2。
gRPC是REST的一個有力替代方案,但像REST一樣,它也是一種同步通信機制,因此也存在部分失敗的問題。
使用異步消息傳遞模式通信
使用消息傳遞時,服務通過異步交換消息進行通信。基于消息傳遞的應用通常使用消息代理,其作為服務之間的中介。服務客戶端通過發送消息向服務請求。如果服務實例預期要回復,它會通過發送單獨的消息回復客戶端。由于通信是異步的,客戶端不會阻塞等待回復。相反,客戶端假設回復不會立即收到。
1.消息傳遞概述
根據Gregor Hohpe和Bobby Woolf的《企業集成模式》一書:
消息通過消息通道交換。發送者(應用程序或服務)將消息寫入通道,接收者(應用程序或服務)從通道讀取消息。讓我們先看一下消息,然后再看通道。
2.關于消息
消息由消息頭和消息體組成。
消息頭 是一組名稱-值對,以及描述所發送數據的元數據。除了由消息發送者提供的名稱-值對外,消息頭還包含名稱-值對,例如由發送者或消息傳遞基礎設施生成的唯一消息ID,以及一個可選的返回地址,指定應將回復寫入的消息通道。
消息體 是以文本或二進制格式發送的數據。
消息有幾種不同類型:
- 文檔 — 包含僅數據的通用消息。接收者決定如何解釋它。命令的回復是文檔消息的一個例子。
- 命令 — 包含指示接收者執行某些操作的數據。客戶端發出的消息是命令的一個例子。
- 事件 — 包含描述發生的事件的數據。發布/訂閱消息通常是事件的一個例子。
3.關于消息通道
消息通過消息通道 發送。消息通道是消息傳遞基礎設施的關鍵組成部分。雖然消息是邏輯上的概念,但消息通道通常是由消息代理實例化的具體、物理概念。消息通道有兩種類型:點對點通道和發布-訂閱通道。
下圖展示了它們是如何工作的:
- 點對點通道 將消息從一個發送者傳遞到一個接收者。消息代理確保每條消息恰好被一個接收者消費。這種類型的通道適用于發送命令和發布單一消費者事件。消息代理通常通過將消息放入隊列實現這一點。
- 發布-訂閱通道 將消息從一個發送者傳遞到多個接收者。消息代理確保每條消息被所有接收者消費。這種類型的通道適用于發布事件。消息代理通常通過將消息放入主題實現這一點。
4.消息傳遞的優缺點
使用消息傳遞有幾個優點:
- 它是異步的,不需要客戶端和服務在通信期間都運行。
- 它使您能夠實現發布/訂閱和發布/異步響應風格的通信。
- 它解耦了客戶端和服務。客戶端通過寫入通道請求服務,服務通過從通道讀取消息提供服務。客戶端和服務不直接通信,因此無需相互了解位置。
- 客戶端可以將請求寫入負載均衡器或消息代理上的虛擬隊列,實現服務實例的負載均衡。
- 消息代理會自動將消息發送到服務實例,因此服務實例崩潰時消息不會丟失。
使用消息傳遞有一些缺點:
- 復雜性增加。使用消息傳遞時,您必須編寫代碼來處理消息發送和接收。
- 調試復雜。消息傳遞引入了一種新形式的通信,您必須跟蹤消息的狀態和流動來調試系統。
- 遇到傳遞消息的基礎設施開銷。消息傳遞基礎設施可能會引入開銷,導致某些消息傳遞方案的性能下降。
- 使用消息傳遞時,調試和測試系統變得更復雜。
最后
微服務通信方法的選擇取決于系統的具體需求和設計考量。同步方法(如REST和gRPC)適用于需要及時響應的場景,而異步消息傳遞則在解耦服務、提高系統可靠性和擴展性方面表現出色。理解這些方法的優缺點以及適用場景,是設計高效、可擴展和可靠的微服務架構的關鍵。希望本文能為您的微服務通信方法選擇提供有價值的指導和參考。