微服務間的通訊如何選擇
如果我們想要構建一個生產就緒的系統,那麼必須要權衡所有因素,其中選擇微服務間的連線方法更是其中的一個難點。
作者在本文中介紹了一些常見的通訊方法,並簡要概述了其專案背景以及為何最終選擇了RPC。
在決定微服務間連線方法前,我們需要搞清楚兩個概念:
- 架構風格(Architectural Style)
- 傳輸協議(Transport Protocol)
架構風格
在使用服務時如何形成有效負載?是有狀態還是無狀態?我們應該採用REST、SOAP、JSON、XML,還是其他訊息格式?
傳輸協議
我們應該用哪種傳輸協議?應該採用HTTP、HTTP2、訊息匯流排、TCP socket,還是UDP?
時下流行的通訊方法
一些主流的選項如下:
- REST over HTTP(S)
- 通過Message Broker進行訊息傳遞
- RPC (跨語言或單語言)
REST over HTTP(S)
自Roy Fielding提出RESTful架構自提出以來,一直都是備受歡迎的方案,特別是在Web應用的開發中。Fielding提出的約束雖然不是標準,但在宣告我們的API為RESTful之前,應該始終遵循這些約束。
HTTP上有各種各樣的REST,因為沒有強制執行的標準。開發人員可以自由選擇以JSON、XML或某種自定義格式形成請求有效負載。
REST over HTTP(S)僅意味著使用REST架構風格並通過HTTP(S)傳送請求。
例如:JSON-RPC
通過Message Broker進行訊息傳遞
該選項基本上通過將微服務連線到集中訊息匯流排來工作,並且服務之間的所有通訊都通過backbone傳送訊息來完成。
例如:Python中的Nameko
RPC (跨語言或單語言)
遠端過程呼叫在分散式系統中並不新鮮,它通過在網路上的另一個裝置上執行函式/方法/過程來工作。
按照RPC標準,RPC 5531:
- RPC應該與傳輸協議無關:TCP、UDP、egal!因此,不保證可靠性
- 事務ID用於確保最多一次的semactics,並允許客戶端應用程式匹配對呼叫的回覆
- 超時和重新連線需要處理伺服器崩潰,即使使用了面向連線的協議(TCP)
- 不指定服務和客戶機的繫結,具體由實現人員決定
- RPC實現的強制性要求:
- 被呼叫過程的唯一規範
- 響應訊息與請求訊息匹配的規定
- 對呼叫方進行服務身份驗證的規定,反之亦然
例如:gRPC RPyC
專案背景
我們有一個一體化Web應用(用Django編寫),效能尚可接受。有些服務可以作為單獨的服務解耦。我正在以漸進的方式將我們的系統架構轉變為微服務架構,其中一項重要工作是決定通訊方式。
為什麼選擇RPC
有很多文章主張用REST替換RPC,說RPC是屬於“石器時代”的技術,但也有人說RPC簡單易用。而我的立場是中立的,要根據實際的專案來做選擇。
以下是專案的主要要求:
- 沒有單點故障 -> 排除訊息佇列傳遞
- 錯誤返回給呼叫者/客戶端/消費者
- 提供原生體驗的服務介面
由於對呼叫方的錯誤返回對我們很重要,RPC是一個很好的候選,因為許多RPC框架將伺服器函式中出現的任何異常返回給RPC函式呼叫方。
大多數RPC框架消除了message broker的需要,因此避免了單點故障。
大多數RPC框架允許遠端過程呼叫,如:
import my_remote_function
try:
my_remote_function.validate_user(my_user)
except ValueError as e:
logging.error(e.message)
還有比RPC更好的選項嗎?
RPC框架的類別
RPC框架大致可分為以下兩種:
- 單語言PRC框架
- 跨語言PRC框架
單語框架,僅支援單一程式語言。在Python中這類類別的一個很好的候選者是RPyC。RPyC具有易於使用的標準RPC功能,並使用TCP作為其傳輸協議。
使用RPyC(單語框架)的優點是不需要編寫單獨的服務介面。缺點是對不同Python版本的支援不足,當然,正如其名稱所暗示的那樣,缺少對跨語言的支援。
跨語言RPC框架支援多種程式語言,但成本很高。gRPC是我使用的框架之一。
gRPC由Google提供支援,涵蓋了從C++、Ruby、Python到Dart的各種程式語言。為了支援多種程式語言,必須定義一個通用的服務契約,通常是協議緩衝區(.proto)檔案。Service Contract使用伺服器提供的引數定義函式,以及要傳輸的訊息格式。對於gRPC,將協議緩衝區檔案編譯為特定語言的檔案(例如Python中的.py檔案),這會在您開始擁有多個版本的service contact時產生問題。這使我們很難跟蹤不同版本的客戶端存根和服務功能。
小結
總結來說,通訊方式需要case by case地選擇,而這些以上基本上是我在選擇微服務之間的通訊媒介時所考慮的問題。