天天看點

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

,有趣實用的分布式架構頻道。

回顧視訊以及 PPT 檢視位址見文末。歡迎加入直播互動釘釘群 : 21992058,不錯過每場直播。

本文根據 SOFAChannel#13 直播分享整理,主題:雲原生網絡代理 MOSN 多協定機制解析。

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

大家好,我是今天的講師無鈎,目前主要從事螞蟻金服網絡代理相關的研發工作,也是 MOSN 的 Committer。今天要和大家分享的是《雲原生網絡代理 MOSN 多協定機制解析》,并介紹對應的私有協定快速接入實踐案例以及對 MOSN 實作多協定低成本接入的設計進行解讀。

我們将按以下順序進行介紹:

  • 多協定機制産生的背景與實踐痛點;
  • 常見的協定擴充思路初探;
  • SOFABolt 協定接入實踐;(重點)
  • MOSN 多協定機制設計解讀;(重點)
  • 後續規劃及展望;

其中第三點「接入實踐」是今天分享的重點,希望能給大家就「如何在 MOSN 中快速擴充私有協定接入」有一個具體的感受。另外「MOSN 如何實作多協定架構」也是很多人關心和問題,我們将摘選幾個技術功能,對其背後的設計思考進行解讀。

MOSN 簡介

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

雲原生網絡代理 MOSN 定位是一個全棧的網絡代理,支援包括網絡接入層(Ingress)、API Gateway、Service Mesh 等場景,目前在螞蟻金服内部的核心業務叢集已經實作全面落地,并經受了 2019 年雙十一大促的考驗。今天要向大家介紹的是雲原生網絡代理 MOSN 核心特性之一的多協定擴充機制,目前已經支援了包括 SOFABolt、Dubbo、TARS 等多個協定的快速接入。

MOSN:

https://github.com/mosn

多協定機制産生的背景與實踐痛點

首先介紹一下多協定機制産生的背景。

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

前面提到,螞蟻金服 2019 年雙十一核心鍊路百分之百 Mesh 化,是業界當時已知的最大規模的 Service Mesh 落地,為什麼我們敢這麼做?因為我們具備能夠讓架構平滑遷移的方案。"相容性"是任何架構演進更新都必然要面對的一個問題,這在早已實踐微服務化架構的螞蟻金服内部同樣如此。為了實作架構的平滑遷移,需要讓新老節點的外在行為盡可能的表現一緻,進而讓依賴方無感覺,這其中很重要的一點就是保持協定相容性。

是以,我們需要在 Service Mesh 架構下,相容現有微服務體系中的通信協定——也就是說需要在 MOSN 内實作對目前螞蟻金服内部通信協定的擴充支援。

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

基于 MOSN 本身的擴充機制,我們完成了最初版本的協定擴充接入。但是在實踐過程中,我們發現這并不是一件容易的事情:

  • 相比編解碼,協定自身的處理以及與架構內建才是其中最困難的環節,需要了解并實作包括請求生命周期、多路複用處理、連結池等等機制;
  • 社群主流的 xDS 路由配置是面向 HTTP 協定的,無法直接支援私有協定,存在适配成本;

基于這些實踐痛點,我們設計了 MOSN 多協定架構,希望可以降低私有協定的接入成本,加快普及 ServiceMesh 架構的落地推進。

常見的協定擴充思路初探

前面介紹了背景,那麼具體協定擴充架構要怎麼設計呢?我們先來看一下業界的思路與做法。

協定擴充架構 - Envoy

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

注:圖檔來自 Envoy 分享資料

第一個要介紹的是目前發展勢頭強勁的 Envoy。從圖上可以看出,Envoy 支援四層的讀寫過濾器擴充、基于 HTTP 的七層讀寫過濾器擴充以及對應的 Router/Upstream 實作。如果想要基于 Envoy 的擴充架構實作 L7 協定接入,目前的普遍做法是基于 L4 filter 封裝相應的 L7 codec,在此基礎之上再實作對應的協定路由等能力,無法複用 HTTP L7 的擴充架構。 

協定擴充架構 - Nginx

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

第二個則是老牌的反向代理軟體 Nginx,其核心子產品是基于 Epoll/Kqueue 等 I/O 多路複用技術之上的離散事件架構,基于事件架構之上建構了 Mail、Http 等協定子產品。與 Envoy 類似,如果要基于 Nginx 擴充私有協定,那麼也需要自行對接事件架構,并完整實作包括編解碼、協定處理等能力。

協定擴充架構 - MOSN

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

最後回過頭來,我們看一下 MOSN 是怎麼做的。實際上,MOSN 的底層機制與 Envoy、Nginx 并沒有核心差異,同樣支援基于 I/O 多路複用的 L4 讀寫過濾器擴充,并在此基礎之上再封裝 L7 的處理。但是與前兩者不同的是,MOSN 針對典型的微服務通信場景,抽象出了一套适用于基于多路複用 RPC 協定的擴充架構,屏蔽了 MOSN 内部複雜的協定處理及架構流程,開發者隻需要關注協定本身,并實作對應的架構接口能力即可實作快速接入擴充。

三種架構成本對比

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

最後對比一下,典型微服務通信架構協定接入的成本,由于 MOSN 針對此類場景進行了架構層面的封裝支援,是以可以節省開發者大量的研發成本。

SOFABolt 協定接入實踐

初步了解多協定架構的設計思路之後,讓我們以 SOFABolt 協定為例來實際體驗一下協定接入的過程。

SOFABolt 簡介

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

這裡先對 SOFABolt 進行一個簡單介紹,SOFABolt 是一個開源的輕量、易用、高性能、易擴充的  RPC 通信架構,廣泛應用于螞蟻金服内部。

SOFABolt:

https://github.com/sofastack/sofa-bolt

基于 MOSN 的多協定架構,實際編寫了 7 個代碼檔案,一共 925 行代碼(包括 liscence、comment 在内)就完成了接入。如果對于協定本身較為熟悉,且具備一定的 MOSN/Golang 開發經驗,甚至可以在一天内就完成整個協定的擴充,可以說接入成本是非常之低。

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

Github:

https://github.com/mosn/mosn/tree/master/pkg/protocol/xprotocol/bolt

下面讓我們進入正題,一步一步了解接入過程。

Step1:确認協定格式

第一步,需要确認要接入的協定格式。為什麼首先要做這個,因為協定格式是一個協定最基本的部分,有以下兩個層面的考慮:

  • 任何協定特性以及協定功能都能在上面得到一些展現,例如有無 requestId/streamId 就直接關聯到協定是否支援連接配接多路複用;
  • 協定格式與封包模型直接相關,兩者可以構成邏輯上的映射關系;而這個映射關系也就是所謂的編解碼邏輯;
雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

以 SOFABolt 為例,其第一個位元組是協定 magic,可以用于校驗目前封包是否屬于 SOFABolt 協定,并可以用于協定自動識别比對的場景;第二個位元組是 type,用于辨別目前封包的傳輸類型,可以是 Request / RequestOneway / Response 中的一種;第三個位元組則是目前封包的業務類型,可以是心跳幀,RPC 請求/響應等類型。後面的字段就不一一介紹了,可以發現,了解了協定格式本身,其實對于協定的特性支援和模型編解碼就了解了一大半,是以第一步協定格式的确認了解是重中之重,是後續一切工作開展的前提。

Step2:确認封包模型

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

順應第一步,第二步的主要工作是确認封包程式設計模型。一般地,在第一步完成之後,應當可以很順利的建構出相應的封包模型,SOFABolt 例子中可以看出,模型字段設計基本與協定格式中的 header / payload 兩部分相對應。有了程式設計模型之後,就可以繼續進行下一步——基于模型實作對應的架構擴充了。

Step3:接口實作 - 協定

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

協定擴充,顧名思義,是指協定層面的擴充,描述的是協定自身的行為(差別于封包自身)。

目前多協定架構提供的接口包括以下五個:

  • Name:協定名稱,需要具備唯一性;
  • Encoder:編碼器,用于實作從封包模型到協定傳輸位元組流的映射轉換;
  • Decoder:解碼器,用于實作從協定傳輸位元組流到封包模型的映射轉換;
  • Heartbeater:心跳處理,用于實作心跳保活封包的構造,包括探測發起與回複兩個場景;
  • Hijacker:錯誤劫持,用于在特定錯誤場景下錯誤封包的構造;

Step3:接口實作 - 封包

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

前面介紹了協定擴充,接下裡則是封包擴充,這裡關注的是單個請求封包需要實作的行為。

目前架構抽象的接口包括以下幾個:

  • Basic:需要提供 GetStreamType、GetHeader、GetBody 幾個基礎方法,分别對應傳輸類型、頭部資訊、載荷資訊;
  • Multiplexing:多路複用能力,需要實作 GetRequestId 及 SetRequestId;
  • HeartbeatPredicate:用于判斷目前封包是否為心跳幀;
  • GoAwayPredicate:用于判斷目前封包是否為優雅退出幀;
  • ServiceAware:用于從封包中擷取 service、method 等服務資訊;

舉個例子

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

這裡舉一個例子,來讓大家對架構如何基于接口封裝處理流程有一個體感:服務端心跳處理場景。當架構收到一個封包之後:

  • 根據封包擴充中的 GetStreamType 來确定目前封包是請求還是響應。如果是請求則繼續 2;
  • 根據封包擴充中的 HeartbeatPredicate 來判斷目前封包是否為心跳包,如果是則繼續 3;
  • 目前封包是心跳探測(request + heartbeat),需要回複心跳響應,此時根據協定擴充中的 Heartbeater.Reply 方法構造對應的心跳響應封包;
  • 再根據協定擴充的 Encoder 實作,将心跳響應封包轉換為傳輸位元組流;
  • 最後調用 MOSN 網絡層接口,将傳輸位元組流回複給發起心跳探測的用戶端;

當協定擴充與封包擴充都實作之後,MOSN 協定擴充接入也就完成了,架構可以依據協定擴充的實作來完成協定的處理,讓我們實際示範一下 SOFABolt 接入的 example。

Demo 位址:

https://github.com/mosn/mosn/tree/master/examples/codes/sofarpc-with-xprotocol-sample

MOSN 多協定機制設計解讀

通過 SOFABolt 協定接入的實踐過程,大家對如何基于 MOSN 來做協定擴充應該有了一個初步的認知。那麼 MOSN 多協定機制究竟封裝了哪些邏輯,背後又是如何思考設計的?接下來将會挑選幾個典型技術案例為大家進行解讀。

協定擴充架構

協定擴充架構 -  編解碼

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

最先介紹的是編解碼機制,這個在前面 SOFABolt 接入實踐中已經簡單介紹過,MOSN 定義了編碼器及解碼器接口來屏蔽不同協定的編解碼細節。協定接入時隻需要實作編解碼接口,而不用關心相應的接口調用上下文。

協定擴充架構 - 多路複用

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

接下來是多路複用機制的解讀,這也是流程中相對不太好了解的一部分。首先明确一下連結多路複用的定義:允許在單條連結上,并發處理多個請求/響應。那麼支援多路複用有什麼好處呢?

以 HTTP 協定演進為例,HTTP/1 雖然可以維持長連接配接,但是單條連結同一時間隻能處理一個請求/相應,這意味着如果同時收到了 4 個請求,那麼需要建立四條 TCP 連結,而建鍊的成本相對來說比較高昂;HTTP/2 引入了 stream/frame 的概念,支援了分幀多路複用能力,在邏輯上可以區分出成對的請求 stream 和響應 stream,進而可以在單條連結上并發處理多個請求/響應,解決了 HTTP/1 連結數與并發數成正比的問題。

類似的,典型的微服務架構通信協定,如 Dubbo、SOFABolt 等一般也都實作了連結多路複用能力,是以 MOSN 封裝了相應的多路複用處理流程,來簡化協定接入的成本。讓我們跟随一個請求代理的過程,來進一步了解。

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理
  1. MOSN 從 downstream(conn=2) 接收了一個請求 request,依據封包擴充多路複用接口 GetRequestId 擷取到請求在這條連接配接上的身份辨別(requestId=1),并記錄到關聯映射中待用;
  2. 請求經過 MOSN 的路由、負載均衡處理,選擇了一個 upstream(conn=5),同時在這條連結上建立了一個請求流(requestId=30),并調用文擴充多路複用接口 SetRequestId 封裝新的身份辨別,并記錄到關聯映射中與 downstream 資訊組合;
  3. MOSN 從 upstream(conn=5) 接收了一個響應 response,依據封包擴充多路複用接口 GetRequestId 擷取到請求在這條連接配接上的身份辨別(requestId=30)。此時可以從上下遊關聯映射表中,根據 upstream 資訊(connId=5, requestId=30) 找到對應的 downstream 資訊(connId=2, requestId=1);
  4. 依據 downstream request 的資訊,調用文擴充多路複用接口 SetRequestId 設定響應的 requestId,并回複給 downstream;

在整個過程中,架構流程依賴的封包擴充 Multiplexing 接口提供的能力,實作了上下遊請求的多路複用關聯處理,除此之外,架構還封裝了很多細節的處理,例如上下遊複用記憶體塊合并處理等等,此處限于篇幅不再展開,有興趣的同學可以參考源碼進行閱讀。

統一路由架構

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

接下來要分析的是「統一路由架構」的設計,此方案主要解決的是非 HTTP 協定的路由适配問題。我們選取了以下三點進行具體分析:

  • 通過基于屬性比對(attribute-based)的模式,與具體協定字段解耦;
  • 引入層級路由的概念,解決屬性扁平化後帶來的線性比對性能問題;
  • 通過變量機制懶加載的特定,按需實作深/淺解包;

統一路由架構 – 基于屬性比對

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

首先來看一下典型的 RDS 配置,可以看到其中的 domains、path 等字段,對應的是 HTTP 協定裡的域名、路徑概念,這就意味着其比對條件隻有 HTTP 協定才有字段能夠滿足,配置結構設計是與 HTTP 協定強相關的。這就導緻了如果我們新增了一個私有協定,無法複用 RDS 的配置來做路由。

那麼如何解決配置模型與協定字段強耦合呢?簡單來說就是把比對字段拆分為扁平屬性的鍵值對(key-value pair),比對政策基于鍵值對來處理,進而解除了比對模型與協定字段的強耦合,例如可以配置 key: $http_host,也可以配置 key:$dubbo_service,這在配置模型層面都是合法的。

但是這并不是說比對就有具體協定無關了,這個關聯仍然是存在的,隻是從強耦合轉換為了隐式關聯,例如配置 key: $http_host,從結構來說其與 HTTP 協定并無耦合,但是值變量仍然會通過 HTTP 協定字段來進行求值。

統一路由架構 -  層級路由

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

在引入「基于屬性的比對」之後,我們發現了一個問題,那就是由于屬性本身的扁平化,其内在并不包含層級關系。如果沒有層級關系,會導緻比對時需要周遊所有可能的情況組合,大量條件的場景下比對性能近似于線性的 O(n),這顯然是無法接受的。 

舉例來說,對于 HTTP 協定,我們總是習慣與以下的比對步驟:

  • 比對 Host(:authority) ;
  • 比對 Path ;
  • 比對 headers/args/cookies ;

這其實構成了一個層級關系,每一層就像是一個索引,通過層級的索引關系,在大量比對條件的情況下仍然可以獲得一個可接受的耗時成本。但是對于屬性(attribute),多個屬性之間并沒有天然的層級關系(相比于 host、path 這種字段),這依賴于屬性背後所隐式關聯的字段,例如對于 Dubbo 協定,我們希望的順序可能是:

  • 比對 $dubbo_service;
  • 比對 $dubbo_group;
  • 比對 $dubbo_version;
  • 比對 $dubbo_attachments_xx;

是以在配置模型上,我們引入了對應的索引層級概念,用于适配不同協定的結構化層級路由,解決扁平屬性的線性比對性能問題。

統一路由架構 - 淺解包優化

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

最後,介紹一下淺解包優化的機制。利用 MOSN 變量懶加載的特性,我們可以在封包解析時,先不去解析成本較高的部分,例如 dubbo 協定的 attachments。那麼在代理請求的實際過程中,需要使用到 attachments 裡的資訊時,就會通過變量的 getter 求值邏輯來進行真正的解包操作。依靠此特性,可以大幅優化在不需要深解包的場景下 dubbo 協定代理轉發的性能表現,實作按需解包。

解讀總結

最後,對設計部分的幾個技術案例簡單總結一下,整體的思路仍然是對處理流程進行抽象封裝,并剝離可擴充點,進而降低使用者的接入成本。

在協定擴充支援方面:

  • 封裝編解碼流程,抽象編解碼能力接口作為協定擴充點
  • 封裝協定處理流程,抽象多路複用、心跳保活、優雅退出等能力接口作為協定擴充點

在路由架構方面:

  • 通過改為基于屬性比對的機制,與具體協定字段解耦,支援多協定适配;
  • 引入層級路由機制,解決屬性扁平化的比對性能問題;
  • 利用變量機制懶加載特性,按需實作深/淺解包;

後續規劃及展望

更多流模式支援、更多協定接入

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

目前 MOSN 多協定機制,已經可以比較好的支援像 Dubbo、SOFABolt 這樣基于多路複用流模型的微服務協定,後續會繼續擴充支援的類型及協定,例如經典的 PING-PONG 協定、Streaming 流式協定,也歡迎大家一起參與社群建設,貢獻你的 PR。

社群标準方案推進

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

與此同時,我們注意到 Istio 社群其實也有類似的需求,希望設計一套協定無關的路由機制——"Istio Meta Routing API"。其核心思路與 MOSN 的多協定路由架構基本一緻,即通過基于屬性的路由來替代基于協定字段的路由。目前該草案還處于一個比較初級的階段,對于比對性能、字段擴充方面還沒有比較完善的設計說明,後續 MOSN 團隊會積極參與社群方案的讨論,進一步推動社群标準方案的落地。

以上就是本期分享的全部内容,如果大家對 MOSN 有問題以及建議,歡迎在群内與我們交流。

本期視訊回顧以及 PPT 檢視位址

https://tech.antfin.com/community/live/1131

MOSN Logo 社群投票結果公示

MOSN 的 Logo 更新,在進過社群投票後,在本期直播結束後截止。截止 2020年3月26日20:00,有效票數 35 票。方案一 25 票,占比 71.43%;方案二 2 票,占比 5.71%;方案三 8 票,占比 22.86%。最終,方案一大比分勝出,方案一 為 MOSN 最終 Logo 。感謝大家參與社群投票~

雲原生網絡代理 MOSN 多協定機制解析 | SOFAChannel#13 直播整理

恭喜以下社群同學,你們投票與最終結果一緻~Github ID

@CodingSinger @trainyao @JasonRD @taoyuanyuan @wangfakang @ujjboy @InfoHunter @Tony-Hangzhou @GLYASAI @carolove @tanjunchen @bruce-sha @hb-chen @luxious @echooymxq @qunqiang @f2h2h1 @sunny0826 @token01 @Ayi- @cytyikai @fanyanming2016 @inkinworld @dllen @meua

具體 issue 位址:

https://github.com/mosn/community/issues/2

繼續閱讀