2018年上半年,螞蟻金服決定基於 Istio 訂製自己的 ServiceMesh 解決方案,並在6月底正式對外公佈了 SOFAMesh。
在 SOFAMesh 的開發過程中,針對遇到的實際問題,我們給出了一套名為 x-protocol 的解決方案,本文將會對這個解決方案進行詳細的講解,本篇為最後一篇。
歷史文章:
背景
在 Istio 和 Envoy 中,對通訊協議的支援,主要體現在 HTTP/1.1 和 HTTP/2 上,這兩個是 Istio/Envoy 中的一等公民。而基於 HTTP/1.1 的 REST 和基於 HTTP/2 的gRPC,一個是目前社群最主流的通訊協議,一個是未來的主流,Google 的寵兒,CNCF 御用的 RPC 方案,這兩個組成了目前 Istio 和 Envoy(乃至 CNCF 所有專案)的黃金組合。
而我們 SOFAMesh,在第一時間就遇到和 Istio/Envoy 不同的情況,我們需要支援REST 和 gRPC 之外的眾多協議:
-
SOFARPC:這是螞蟻金服大量使用的 RPC 協議(已開源)
-
HSF RPC:這是阿里集團內部大量使用的 RPC 協議(未開源)
-
Dubbo RPC: 這是社群廣泛使用的 RPC 協議(已開源)
-
其他私有協議:在過去幾個月間,我們收到需求,期望在 SOFAMesh 上執行其他TCP 協議,部分是私有協議
為此,我們需要考慮在 SOFAMesh 和 SOFAMosn 中增加這些通訊協議的支援,尤其是要可以讓我們的客戶非常方便的擴充套件支援各種私有 TCP 協議:
實現分析
我們來大體看一下,在 SOFAMesh/Istio 中要新增一個通訊協議需要有哪些工作:
-
protocol decoder:負責解析協議,讀取協議欄位
-
protocol encoder:負責生成請求報文,注意通常會有改動,比如修改某些header
-
在pilot中需要為新協議生成 Virtual Host 等配置,有 inbound 和 outbound 兩份,分別下發到Sidecar
-
在Sidecar中,根據下發的 Virtual Host 等配置,進行請求匹配,以決定請求該轉發到何處
備註:實際下發的配置不止 Virtual Host 配置,為了簡單起見,我們僅以 Virtual Host 為例做講解。
其中,protocol encoder 和 protocol decoder 是容易理解的,對於新的通訊協議肯定需要有協議編解碼層面的工作必須要完成,這塊有工作量是很自然的。
我們來看看第三塊的工作量是什麼,inbound 和 outbound 的Virtual Host配置示例如下:
outbound 配置中,注意 domains 欄位是各種域名和ClusterIP,而 routes 中,match是通過prefix來匹配。我們結合HTTP/1.1,domains欄位是用來和請求的Host header進行域名匹配的,比如 Host: istio-telemetry
,這決定了哪些請求是要轉發到 istio-telemetry 這個服務的。routes的match用來進行路由匹配的,通過HTTP請求的path進行匹配。
inbound 配置類似,只是inbound更簡單,domains 匹配*
就可以。
從上面的例子中可以看到,Istio 和 Envoy 的設計有非常濃重的HTTP協議的味道,各種語義都是和 HTTP 直接相關。而當我們進行 TCP 協議的轉發時,就需要將請求的協議欄位進行對映,對映到 HTTP 的相應語義。
比如,最基本的 Destination,原始語義是請求的目的地,在前面的文章中我們指出過這是請求轉發最關鍵的欄位。在 HTTP 協議中,通常是通過 Host header 和 Path 表示,對於 REST 而言還有重要的 Method 欄位。
下面的格式是其他各種協議對這個 Destination 原始語義的實際實現方式:
協議 | 實現 |
---|---|
原始語義 | 請求的目的地(Destination) |
HTTP/1.1 | Host header,Method,Path |
HTTP/2 | Header幀中的偽header :authority ,:path 和:method |
Bolt協議 | header map中key為”service”的欄位 |
HSF協議 | 協議頭中的服務介面名和服務方法名 |
Dubbo協議 | data欄位(payload)中的path/method |
這些通訊協議在下發規則和進行請求匹配時,就需要進行協調:
-
定義好 Virtual Host 配置中的 domains 欄位和 route 中的 match 用到的欄位在當前通訊協議中的實際語義
-
在 protocol encoder 中讀取請求的協議欄位,和上面的欄位對應
-
然後進行請求路由規則匹配(參照 HTTP/1.1中的 domain 和 route match 的匹配)
而這些都是需要以程式碼的方式進行實現,以滿足新通訊協議的要求。正規的做法,是每次新增一個通訊協議就將上述的工作內容重複一遍。這會直接導致大量的高度類似的重複程式碼。
x-protocol的實現
在上述需要在協議擴充套件時修改的四個內容中,有一塊是特別的:生成 Virtual Host 配置的工作是在 Pilot 中實現的,而其他三個是在 Sidecar ( Envoy 或 MOSN )中。考慮到 protocol encoder 和 protocol decoder 的工作是必不可少的,必然會修改Sidecar來增加實現程式碼,因此簡化開發的第一個想法就是:能不能做到不修改Pilot?
基本思路就是固定好原始語義,避免每個通訊協議都對映一遍。從前面我們列出來的各個協議的對映情況看,對於RPC協議而言,一般目的地資訊都是服務名(有些是介面名)+方法名居多,因此可以考慮直接將服務名和方法名固定下來:
-
RPC協議在 Virtual Host 配置中就固定為服務名對應 domains 欄位,方法名對應 route 中的 match 用到的欄位,這樣只要修改一次然後各個 RPC 協議公用此配置,以後就不用再重複修改 Pilot。
-
protocol encoder 在解析通訊協議完成之後,就直接將協議中對應服務名和方法名的欄位提取出來,後面的匹配處理過程就可以公用一套通用實現,這樣路由匹配這塊也可以不用在重複開發。
因此,在x-protocol中,如果需要引入一個新的通訊協議,需要的工作內容只有必不可少的 protocol encoder 和 protocol decoder,和實現以下幾個介面:
總結
X-protocol 在支援新通訊協議上的做法並無新奇之處,只是由於需求特殊有眾多通訊協議需要支援,在開發時發現大量重複工作,因此我們選擇了一條可以讓後面更舒服一點的道路。
目前這個方案在 SOFAMesh 中採用,我們將進一步檢驗實際效果,也會和合作的小夥伴時驗證,看他們在自行擴充套件新協議時是否足夠理想。這個方案理論上應該可以同樣適用於 Istio、Envoy 體系,隨著社群對Istio的接受程度的提高,在 Istio 上支援各種TCP 通訊協議的需求會越來越多,有理由相信Istio後續可能也會出現類似的方案。畢竟,每次都改一大堆類似的東西,不是一個好做法。
相關連結:
SOFA 文件: http://www.sofastack.tech
SOFA: https://github.com/alipay
SOFAMosn:
https://github.com/alipay/sofa-mosn
SOFAMesh:
https://github.com/alipay/sofa-mesh
推薦閱讀
螞蟻金服SOFAMesh在多語言上的實踐 | CNUTCon 實錄
開源 | Service Mesh 資料平面 SOFAMosn 深層揭祕
螞蟻金服Service Mesh新型網路代理的思考與實踐 | GIAC 分享實錄
長按關注,獲取分散式架構乾貨
歡迎大家共同打造 SOFAStack https://github.com/alipay