朵曉東,花名奕杉,螞蟻金服高階技術專家。專注企業雲端計算技術及產品,螞蟻金融雲 PaaS 創始團隊核心成員,Antstack 網路產品負責人。開源愛好者,Apache Kylin 創始團隊核心成員;SOFAMesh 創始團隊核心成員,SOFAMosn 專案負責人。
本文根據曉東在 GIAC 上海站的演講內容整理,完整的分享 PPT 獲取方式見文章底部。
大家好,我是螞蟻金服系統部的高階技術專家奕杉,今天分享的內容是:《螞蟻金服在 ServiceMesh 推進落地過程中對新型網路代理的思考和實踐》
內容結構:
主要的分享順序:
-
背景概述
-
架構設計及功能特性
-
技術案例
-
總結展望
1、背景、概覽:
ServiceMesh 作為雲原生之上的服務網格技術在今年引起了業界的廣泛關注,首先我們來看一下目前 ServiceMesh 資料平面的一些方案。
最為大家熟知的是老牌七層代理 Nginx 和 ISTIO 原生的資料平面 Envoy。Nginx 早已在國內外廣泛使用,近兩年積極探索 K8S、ServiceMesh 微服務場景,並推出了與 ISTIO 整合的微服務解決方案,試圖擴充套件其場景邊界,拿下新的領域,從單純的7層流量代理到雲原生時代的智慧資料平面轉型。但目前看 “NgMesh”研發不夠活躍,已知的使用方也不多。Envoy 作為 Google 和 Lyft聯合開發的 ISTIO 原生資料平面產品,近兩年藉助 ServiceMesh 微服務場景快速開啟了市場,並在一些網際網路公司推廣使用,同時引入了一批開發者進行 API 閘道器等功能閘道器的開發,發展勢頭非常好。
其次 LINKERD 是基於 Rust 的一種高效能資料平面,但其發展空間受到了 Envoy 擠壓,業界使用的公司也比較有限。
螞蟻金服基於自身訴求自研了基於 Golang 的資料平面 SOFAMosn(後簡稱MOSN),並在螞蟻、UC 等公司落地使用。
同時對業界開源,提供了一種新的資料平面產品選擇。
此外國內的華為、新浪等公司都基於自身場景提出了資料平面方案並先後進行了開源,資料平面競爭已經從獨霸業界的基於 Nginx 二開方案逐步轉變為目前的多樣化產品同場競技的局面。
為什麼眾多大廠紛紛投入研發資料平面呢?
我個人認為新生技術棧、雲原生、微服務快速發展等契機對資料平面提出了場景多樣化、功能服務化、雲原生親和等多重挑戰。
以往從未像現在這樣對資料平面提出過如此多的要求:
-
資料平面需要執行部署運維中的流量切換;
-
需要提供雲親和的細粒度流量排程功能;
-
需要提供微服務親和的服務發現、路由組網特性;
-
需要以雲原生的方式感知資源;
-
需要支撐服務粒度、高度自定義的壓測、故障測試、線上灰度流量管理;
-
需要提供鏈路級、服務級的安全隔離保護,需要支援多種語言、多種協議的轉換分發能力;
-
需要能享受系統層面、硬體層面的紅利;
-
需要為複雜的運維架構(如螞蟻的 LDC 等)提供可擴充套件的流量調撥能力等等;
-
當然根據每個公司的業務場景可能還有其他的因素。 最後,如何要將這些能力都匯聚在統一的資料平面產品上,彌合南北向、東西向資料平面由於技術棧、團隊等差異帶來的鴻溝,變成了另一個更為複雜的問題。這裡所提到的問題中任何一點擴充套件開來都可以是一個豐富獨立的 Topic,受限於篇幅本次分享只能介紹我們在解決這些問題中的一小部分思考和實踐。
2、SOFAMesh 架構 & 重點特性
首先,螞蟻已經將基於 ISTIO 的 ServiceMesh 方案 “SOFAMesh” 開源,在控制面我們選擇克隆 ISTIO 官方版本並研發符合螞蟻需求的控制面,在資料面我們選擇使用 Golang 研發資料平面 MOSN,目前已經支援了微服務場景所需的大量常用功能。
這裡我根據 ISTIO 的 Task 文件總結了目前 SOFAMesh 支援的一些能力,如:透明攔截適配,細粒度的流控,故障注入,雙向鏈路加密等。對於一些暫時存疑的功能,如 Mixer Check 等,暫時沒有支援。目前 SOFAMesh 已在 UC 生產環境落地使用,滿足了 Sidecar、Ingress、Egress 多種場景的使用需求。在這裡附上 SOFAMesh,SOFAMosn 的 Github 地址,也歡迎大家使用交流。 SOFAMesh:github.com/alipay/sofa… SOFAMosn:github.com/alipay/sofa…
再來看看螞蟻內部,由於目前螞蟻生產環境尚未大量鋪開K8S,並且已經存在一套完善的管控技術體系,加上目前ISTIO 的效能和穩定性還不滿足大規模微服務場景等原因,我們暫時沒有選擇直接升級到 ISTIO,而是通過優先落地Sidecar 的方式來贏得 ServiceMesh 解決方案帶來的紅利。在螞蟻內部,MOSN 接管了SOFABoot 應用,代理了服務發現、路由/負載均衡、通訊等工作,構成了微服務網格,通過自有的中介軟體及管控平面進行微服務的管理、治理。同時,我們積極的推進 MOSN 與 SOFA中介軟體,網路接入層,安全防護及監控體系的整合,以提供更統一更強大的資料平面。
接下來我將介紹 MOSN 支援多協議的方案。
為了在內部快速落地試錯,我們首先支援了內部使用最廣泛的 SOFARPC 協議,並對其進行了深度優化。隨後我們根據 UC Mesh 化推進遇到的普遍問題提出了 XProtocol 方案,以在不解包的場景下提供路由能力。最後我們深度改造了三方 HTTP/1.1 實現及官方 HTTP/2.0 實現。到目前為止,MOSN 已提供了多種協議的支援。同時 MOSN 提供了兩種自定義協議的能力支援使用者通過擴充套件的方式自定義協議實現,滿足需要解包、不需要解包的協議擴充套件需求。
除協議之外,效能是大家比較關心的另一個問題。為了提供滿足生產要求的7層轉發效能,我們在 IO、協議、記憶體、協程、網路處理等方面進行了優化,從目前通過 SOFARPC 通訊應用的上線情況來看可以滿足生產使用要求,在案例分析中我將展示一些效能資料,後續我們也將繼續推進效能優化,以達到更好的效能。
在安全能力上,SOFAMesh 支援 mTLS,並在螞蟻內部整合螞蟻內部的 KMS 完成了 mTLS 落地,同時 RBAC 功能在研發中,此外WAF、流量映象能功能也在規劃中。
在螞蟻內部基於 MOSN 的閘道器產品正在研發中,將會在穩定驗證後開源。閘道器場景相對於 Sidecar 場景有一些特性需求,比如說一般會 Hold 住大量長連結,比如說會根據請求內容動態選擇後端應用,由於閘道器可能代理了不同的後端應用,就會需要動態選擇後端協議。此外還有一些閘道器類的通用能力需求,如簽名,授權,限流等。
為了能基於開源版建設螞蟻內部的 Sidecar 及閘道器產品,我們充分考慮了開源版 MOSN 的擴充套件性,在路由、後端管理、TLS、網路、流處理等各方面提供了擴充套件性支援。對於其他使用 MOSN 的場景,也可以通過類似的方式來滿足自身業務定製需求。
為了更清晰的展示 MOSN 功能特性,這裡將 MOSN 0.4.0 的功能特性通過表格的方式展示出來。可以說0.4.0版本已經初步具備了生產所需的大部分功能點,支援雲原生場景下的多協議、路由&LB、後端管理、TLS、遙感監測、XDS對接等功能,並充分優化了效能,目前已經在螞蟻、UC生產環境進行了驗證。同時在螞蟻內部我們通過擴充套件的方式支援了灰度路由、 LDC 路由、彈性路由,支援了配置中心等定製需求。後續我們會繼續完善功能點,如果有發現未支援的功能可以在 Github 給我們提 Issue,或者直接加入我們 commit code。由於MOSN在擴充套件性上提供了比較好的能力支援,在特定的場景都可以通過擴充套件的方式來滿足需求。
3、技術案例解析
在介紹了架構、功能特性以後,我將介紹一些落地過程中的技術案例。
首先我們來看在螞蟻在非 K8S 場景下將 MOSN 作為 Sidecar 接入應用的姿勢。 在我們推進落地初期,需要接入MOSN 的 SOA 應用還沒有通過原生 K8S 的方式執行起來,服務發現是基於典型的服務發現中介軟體來做,也沒有直接使用 ISTIO 來落地。在這種情況下,我們通過擴充套件開源版 MOSN 支援服務發現,將 MOSN 作為服務代理,由其完成服務 Pub/Sub,並代理服務完成 RPC 通訊。這裡有幾個要點,首先由於核心限制我們沒有第一時間使用Iptables 攔截請求,而是通過升級 SOFA 的方式來支援應用切換訪問地址,這裡需要應用方升級 SOFA 依賴,但不需要改業務程式碼。
其次,我們通過擴充套件開源版服務發現實現的方式支援從螞蟻配置中心獲取後端服務列表。在路由生成上,MOSN 基於完善的服務間依賴關係生成服務路由,由於 SOFA 應用在編碼階段已明確定義了服務依賴並在服務啟動時由 MOSN 代理完成 Pub/Sub,MOSN 感知所需的服務依賴關係,並動態生成了出向/入向路由。如果你的使用場景服務之間沒有明確的依賴關係,則需要擴充套件路由機制支援基於完全請求內容的動態路由機制。其次,SOFA 服務定址基於明確的 id:version資訊,所以這樣的服務發現、路由方案同時也適用於類似的 SOA 服務,同時也可以支援標準微服務定址。這樣的擴充套件方式可以實現基於服務發現中介軟體的非 K8S 的 Sidecar 注入,來享受 Mesh 思路落地的便利。
除了通過以上方式支援 SOA 化服務外,SOFAMesh 標準方案提供了一種基於 DNS 的定址方案,以在不修改應用的情況下支援標準微服務定址。 首先通過 DNS 將服務名轉化為 IP,同時在 MOSN 路由的 Virtual Host 中配置服務IP,以及與後端的匹配關係。Client 請求被 Iptables 攔截並轉發給 MOSN,MOSN 在處理請求時通過 Tcp Option 的 Original Destination 項拿到目標 IP,並作為 Host 與 Virtual Host 匹配定址到 Cluster 並做後端 LB及轉發。這樣在不進行微服務化改造的情況下就可以進行服務名完成定址通訊了。這裡更多細節可以參考敖小劍老師寫的XProtocol完整方案。
接下來我們一起分析另一個在生產環境非常有用的特性,無損平滑升級。 大部分7層流量代理,包括 Nginx、Envoy等,在升級過程中通常會讓老程式靜默等待一段時間後再退出、或等待時機由新程式控制退出,通過這種方式來保證老程式不再處理到請求。這種方式對於 HTTP/1.x 短連結是比較有用的,但對於 HTTP/1.1長連結、RPC 長連結最終不得不通過暴力斷鏈的方式讓 Client 重連、重試,對業務是有一定影響的。凡會造成業務抖動一般都會造成業務方緊張,這會導致新功能升級推動困難。針對這個問題,MOSN 提出了自己的解決方案,在升級過程中無損遷移存量連結,目前支援 HTTP/1.1、無狀態 RPC、TLS,後續將基於 Goaway 幀支援 HTTP/2.0。下面我們來看看MOSN 是怎麼實現這樣能力的。
這裡我把典型場景抽象成 Client 請求處理和 Server 回覆處理兩部分,我們先來看看 Client 請求處理。在升級階段,同時存在新老兩個 MOSN 程式,此時可能存在 Client 正在訪問老程式的情況,此時老程式會通過 Domian Socket 將 TCP1 的 FD 及連結狀態資料傳遞給新程式,由新程式建立 TCP3 連結並將資料傳送到後端 Server 並接收 Server 響應,新程式在收到響應後不再轉發給老程式,直接轉發給 Client 完成本次請求。此後老程式退出 Read流程, 不再接受該 TCP1 連線上的資料,同時新程式開始 Read 流程,接受該 TCP1 連線上的資料,完成 Reload 過程。
再來看看第二種情況,在第一步連結遷移完成後仍然可能出現 Server 通過TCP2 將殘留響應傳送到老程式的情況,此時老程式會通過 Domian Socket 將請求資料傳遞給新程式,由新程式回覆到 Client。這樣就避免了兩個 MOSN程式同時寫到 Client 造成亂序的問題。延伸一下,未來基於這樣的思考可以與容器 fork 結合提供容器、Pod 層面的無損遷移方案。
在遷移過程中我們發現,對於無狀態的 HTTP/1.1 長連結,RPC 長連結遷移較為簡單,但對於有多回合握手的 TLS遷移則比較麻煩,這裡主要涉及到 TLS 的狀態資料遷移,如加密祕鑰,Seq 序列,讀快取資料,Cipher 型別等狀態資料都需要做特殊的處理以保證遷移過程不會破壞握手過程。此外,MOSN 還支援對請求連結做明、密文檢測,來保證上游可以灰度的開啟鏈路加密。
最後我將介紹一下我們在效能優化方面的一些實踐。資料來源於 2018年8月份的 0.2.1 開源版。 先介紹一下在 Sidecar 模式下的效能資料,測試場景是一個典型的服務間通訊場景,服務A 通過 MOSN 訪問服務B。這裡選用的機型是螞蟻內部的測試機器。我們測試的場景包括了 SOFARPC、HTTP/1.1、HTTP/2.0三種協議,測試的工具分別是螞蟻內部的壓測平臺、ab、h2load,其中 HTTP/2.0 壓測 5 條連結的場景,並且是 H2C,無 TLS 加密。資料場景是 1K 的請求、響應。
我們來看一下測試結果,可以看到 SOFARPC 效能遠好於其他兩個協議。需要說明的是,HTTP/1.1 在 0.2.1 版本中直接使用了開源的 FastHTTP,MOSN 沒有接管 IO 處理,協議解析等工作,未做任何優化;HTTP/2.0 直接使用了官方實現,MOSN 沒有接管 IO 處理,協議解析等工作,未做任何優化。
在 SOFARPC 的優化上我們從 IO,協議到上層處理做了不少優化,這裡簡單介紹一些優化經驗。首先分享一個踩過的坑,在基於 Golang Connection API 編寫讀資料程式碼時,一個常用的方式是通過 SetReadDeadline 來設定讀超時,我們發現在讀超時很短的情況下,在2.6.2 核心會比 4.13.0 核心效能下降 30%,而通過綁核可以解決此問題。此外,有很多有用的手段可以用來優化效能,比如說讀合併減少協議處理次數,writev 減少系統呼叫寫的次數可以有效提升整體吞吐量。我們通過對比 Golang 和 OS 的 perf 資料發現 Golang 系統呼叫耗時比 OS 系統呼叫耗時要多(原因還需要進一步明確),減少 Golang 系統排程總是有效的優化手段。在記憶體優化方案,首先可以儘量減少記憶體入堆,對於 100K 以下的記憶體入棧比入堆更快,並且不會影響 GC,對於不得不入堆的記憶體,可以通過有效的記憶體回收複用減少記憶體建立,減少 GC 壓力。其次,在可控的範圍內池化協議可以減少 Golang runtime 排程,並減少為了 Golang 為了保證連續棧而呼叫 morestack 造成的開銷。對於單核的場景,需要關注協程數量及協程使用率,避免協程飢餓的情況。對於 perf 發現的熱點,需要有針對性的進行優化。
接下來看看閘道器的場景,Client 通過 MOSN 訪問 Server,測試條件與單核類似,不過沒有限制 MOSN 的 P,也沒有綁核。
從實驗結果上看,SOFARPC,HTTP/1.1 的結果基本在預期內,但 HTTP/2.0 效能遠低於預期。
我們看到 Golang 官方的 HTTP/2.0 實現在多核場景下效能不佳,在 0.4.0 中對官方 HTTP/2.0 進行了效能優化,我們將在 0.4.0 正式釋出後更新效能資料。在多核場景下我們仍然選擇了單程式模型,根據連線數、負載等變化可以壓到 4-8 核。我們也嘗試了多程式綁核+reuse port 的方案,多核吞吐量高於單程式 15% 以上,但從容器的適配性,程式模型簡單等角度考慮我們仍然選擇了單程式模型。在多核場景下需要特別關注全域性鎖的效能和 IO 的優化,這也是官方 Golang HTTP/2.0 實現效能不佳的重要原因。此外,需要在壓測時關注 G 是否頻繁切換,P 是否有飢餓等問題,有針對性的進行多核效能優化。
我們再來看看長連結的模式,在這種模式下會有大量連結,但不會出現同時有大量流量的情況。MOSN 針對這種場景提供了基於 NetPoll 的使用模式,我們重點壓測了在 10K 連結場景下 SOFARPC 的效能。
從壓測結果上可以看看到,基於 Raw Epoll 的 NetPoll 模式在資源消耗上明顯少於原生 Golang IO 的模式。
從結果上看,原生 IO模式還無法高效能的滿足 C10K 場景的要求,針對高效能閘道器場景還是需要通過更有針對性的方案來支援。
最後我將介紹 TLS 效能資料,這裡通過 Nginx+OpenSSL,Caddy,Caddy+BoringSSL 三種實現來測試 SSL 處理的效能資料。
從測試結果可以看到,對於 RSA 加密,使用了 Golang 原生支援的 Caddy 效能明顯弱與 OpenSSL 及Caddy+BoringSSL,但對於 ECDSA 來說 Caddy 弱於 OpenSSL,但明顯略好於通過 cgo 呼叫 BoringSSL 的方式。
通過進一步分析發現,Golang 對 RSA 的實現是基於 Golang 的,但對 ECDSA 等現代加密演算法有彙編優化,比如說對 p256 的一些重點實現方法是移植了 OpenSSL 實現。同時 Golang 對 AES-GCM,SHA,MD 等演算法都有彙編優化。如果你需要使用的演算法正好在 Golang 的優化範圍內,那麼完全可以直接使用 Golang 原生實現,可以省去對接 OpenSSL、BoringSSL 的麻煩。
最終總結一些效能優化的結果,到目前為止,在 SOFARPC 協議上對 0.1.0 版本 QPS 提升了 50%,記憶體使用減少了 40%;HTTP/2.0 經過一輪優化,QPS 提升了一倍,後續會繼續推進優化;HTTP/1.1 也有 30% 以上的效能提升。
此外,Golang 效能優化與 C/C++ 還是有比較大的區別,在C/C++ 優化過程中,重點觀察系統 perf 進行優化,但Golang 的話需要既需要了解、觀察 Golang runtime 的 perf、排程資料,也需要觀察 OS層面 的 perf 資料,並且需要進行結合分析。一些 C/C++ 常用的方式在 Golang 也無法直接使用,比如說在C中做無鎖替換經常通過整塊記憶體替換指標的方式來保證原子性,但在 Golang 裡指標替換並不是原子的,如果分析彙編會發現實際上執行了多條彙編,在實現層面就需要一些特殊的處理。
由於 Golang 從編譯到執行時,從執行單元到系統呼叫都是一個非常獨立並且自包含的體系,他並沒有基於 C 的開發套件建立,可以說是非常自成一體了,所以在系統層面的整合上仍然有不少問題需要克服,比如說 cgo 效能,但是由於他的優點也是非常明顯的,可以在更多系統軟體場景去探索挖掘,完善實現,建立出基於 Golang 世界的系統軟體體系。
此外,在解決具體問題的過程中我們積累了不少有值得分享的案例,比如說在大流量場景下動態更新存量連結的配置風險策略,Metrics 平滑遷移,支援多層路由判斷的可擴充套件鏈式路由等,受限於篇幅無法一一展開,後續我們將通過blog 或 meetup 的方式與大家分享。
4、總結 & 展望
最後我們再看看微服務場景下 SOFAMosn 落地的方案,首先 SOFAMosn 作為 Sidecar 與 SOFABoot APP 融合代理服務、通訊、配置等功能,與螞蟻的 Control Plane 通訊完成服務配置更新。
最後我們再從整體視角看看 MOSN、MOSNG 在螞蟻架構中的位置。MOSN 作為螞蟻全新的資料平面,會貫穿網路接入、微服務、安全、Serverless 等場景的落地中。我們將推進東西向,南北向技術架構的融合,形成統一的負載網路。在安全方向上,我們將會在微服務級別的安全保障上做更細緻的工作,從 2、3、4、7 層做更多的安全隔離工作,例如做到微服務粒度的流量攔截、牽引。在 Serverless 場景,MOSN 將作為 Serving 的前置提供服務。最後 MOSN 將積極地與使用者態加速技術,7層流量攔截服務等基礎能力整合,更好的服務於統一負載網路。 從螞蟻技術棧演進的視角看,在下一代微服務架構、下一代接入網路、零可信微隔離的技術發展的萌芽之下,MOSN的出現是必然也是偶然,最終將成為新生技術體系落地過程的重點環節,我們將繼續探索,逐步形成適合螞蟻業務場景的資料平面。
我今天要介紹的內容就是這些,歡迎大家關注“金融級分散式架構”,“ServiceMesher” 公眾號,我們將會有更多技術乾貨釋出在公眾號中。同時這裡有 SOFAMesh、SOFAMosn 的 Github 地址,歡迎大家 star,或試用,更歡迎大家為我們提出寶貴意見。謝謝大家。 地址: SOFAMesh: github.com/alipay/sofa… SOFAMosn: github.com/alipay/sofa…