天天看點

SOFAMesh中的多協定通用解決方案x-protocol介紹系列(3)——TCP協定擴充

2018年上半年,螞蟻金服決定基于 Istio 訂制自己的 ServiceMesh 解決方案,并在6月底正式對外公布了 SOFAMesh。

在 SOFAMesh 的開發過程中,針對遇到的實際問題,我們給出了一套名為 x-protocol 的解決方案,本文将會對這個解決方案進行詳細的講解,本篇為最後一篇。

曆史文章:

SOFAMesh中的多協定通用解決方案x-protocol介紹系列(1) : DNS通用尋址方案 SOFAMesh中的多協定通用解決方案x-protocol介紹系列(2):快速解碼轉發
SOFAMesh中的多協定通用解決方案x-protocol介紹系列(3)——TCP協定擴充

背景

在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中的多協定通用解決方案x-protocol介紹系列(3)——TCP協定擴充

實作分析

我們來大體看一下,在SOFAMesh/Istio中要新增一個通訊協定需要有哪些工作:

SOFAMesh中的多協定通用解決方案x-protocol介紹系列(3)——TCP協定擴充
  1. protocol decoder:負責解析協定,讀取協定字段
  2. protocol encoder:負責生成請求封包,注意通常會有改動,比如修改某些header
  3. 在pilot中需要為新協定生成 Virtual Host 等配置,有 inbound 和 outbound 兩份,分别下發到Sidecar
  4. 在Sidecar中,根據下發的 Virtual Host 等配置,進行請求比對,以決定請求該轉發到何處

備注:實際下發的配置不止 Virtual Host 配置,為了簡單起見,我們僅以 Virtual Host 為例做講解。

其中,protocol encoder和protocol decoder是容易了解的,對于新的通訊協定肯定需要有協定編解碼層面的工作必須要完成,這塊有工作量是很自然的。

我們來看看第三塊的工作量是什麼,inbound 和 outbound 的Virtual Host配置示例如下:

SOFAMesh中的多協定通用解決方案x-protocol介紹系列(3)——TCP協定擴充

outbound 配置中,注意 domains 字段是各種域名和ClusterIP,而 routes 中,match是通過prefix來比對。我們結合HTTP/1.1,domains字段是用來和請求的Host header進行域名比對的,比如 

Host: istio-telemetry

,這決定了哪些請求是要轉發到 istio-telemetry 這個服務的。routes的match用來進行路由比對的,通過HTTP請求的path進行比對。

SOFAMesh中的多協定通用解決方案x-protocol介紹系列(3)——TCP協定擴充

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,和實作以下幾個接口:

SOFAMesh中的多協定通用解決方案x-protocol介紹系列(3)——TCP協定擴充

總結

X-protocol 在支援新通訊協定上的做法并無新奇之處,隻是由于需求特殊有衆多通訊協定需要支援,在開發時發現大量重複工作,是以我們選擇了一條可以讓後面更舒服一點的道路。

目前這個方案在SOFAMesh中采用,我們将進一步檢驗實際效果,也會和合作的小夥伴時驗證,看他們在自行擴充新協定時是否足夠理想。這個方案理論上應該可以同樣适用于Istio、Envoy體系,随着社群對Istio的接受程度的提高,在Istio上支援各種TCP通訊協定的需求會越來越多,有理由相信Istio後續可能也會出現類似的方案。畢竟,每次都改一大堆類似的東西,不是一個好做法。

繼續閱讀