大規模服務網格效能優化 | Aeraki xDS 按需載入

騰訊雲原生發表於2021-12-22

作者

鍾華,騰訊雲專家工程師,Istio project member、contributor,專注於容器和服務網格,在容器化和服務網格生產落地方面具有豐富經驗,目前負責 Tencent Cloud Mesh 研發工作。

Istio 在大規模場景下 xDS 效能瓶頸

xDS 是 istio 控制面和資料面 envoy 之間的通訊協議,x 表示包含多種協議的集合,比如:LDS 表示監聽器,CDS 表示服務和版本,EDS 表示服務和版本有哪些例項,以及每個服務例項的特徵,RDS 表示路由。可以簡單的把 xDS 理解為,網格內的服務發現資料和治理規則的集合。xDS 資料量的大小和網格規模是正相關的。

當前 istio 下發 xDS 使用的是全量下發策略,也就是網格里的所有 sidecar,記憶體裡都會有整個網格內所有的服務發現資料。比如下圖,雖然 workload 1 在業務邏輯上只依賴 service 2, 但是 istiod 會把全量的服務發現資料(service 2、3、4)都傳送給 workload 1。

這樣的結果是,每個 sidecar 記憶體都會隨著網格規模增長而增長,下圖是我們對網格規模和記憶體消耗做的一個效能測試,x 軸是網格規模,也就是包含多少個服務例項,y 軸是單個 envoy 的記憶體消耗。可以看出,如果網格規模超過 1萬個例項,單個 envoy 的記憶體超過了 250 兆,而整個網格的開銷還要再乘以網格規模大小。

Istio 當前優化方案

針對這個問題,社群提供了一個方案,就是 Sidecar 這個 CRD,這個配置可以顯式的定義服務之間的依賴關係,或者說可見性關係。比如下圖這個配置的意思就是 workload 1 只依賴 service 2 ,這樣配置以後,istiod 只會下發 service 2 的資訊給 workload 1。

這個方案本身是有效的。但這種方式在大規模場景下很難落地:首先這個方案需要使用者提前配置服務間完整的依賴關係,大規模場景下的服務依賴關係很難梳理清楚,而且通常依賴關係也會隨著業務的變化而變化。

Aeraki Lazy xDS

針對上述問題,TCM 團隊設計了一套無入侵的 xDS 按需載入方案,並開源到 github Aeraki 專案,這是 Lazy xDS 具體的實現細節:

我們在網格里增加2個元件,一個是 Lazy xDS Egress,Egress 充當類似網格模型中預設閘道器角色,另一個是 Lazy xDS Controller,用來分析並補全服務間的依賴關係。

  1. 首先配置 Egress 的服務中轉能力:Egress 會獲取網格內所有服務資訊,並配置所有 HTTP 服務的路由,這樣充當預設閘道器的 Egress 就可以轉發網格內任意 HTTP 服務的流量。

  2. 第2步,對於開啟了按需載入特性的服務(圖中 Workload 1),利用 envoyfilter,將其訪問網格內 http 服務的流量,都路由到 egress。

  3. 第3步,利用 istio sidecar CRD,限制 Workload 1 的服務可見性。

  4. 經過步驟3後,Workload 1 初始只會載入最小化的 xDS。

  5. 當 Workload 1 發起對 Service 2 的訪問時,(因為步驟2)流量會轉發到 Egress。

  6. (因為步驟 1)Egress 會分析接收到的流量特徵,並將流量轉發到 Service 2。

  7. Egress 會將訪問日誌,非同步地上報給 Lazy xDS Controller,上報服務是利用 Access Log Service

  8. Lazy xDS Controller 會對接收到的日誌進行訪問關係分析,然後把新的依賴關係(Workload 1 -> Service 2)表達到 sidecar CRD 中。

  9. 同時 Controller 還會將(步驟2) Workload 1 需要轉發 Service 2 流量到 Egress 的規則去除,這樣未來 workload 1 再次訪問 Service 2 就會是直連。

  10. (因為步驟 8)istiod 更新可見性關係,後續會將 Service 2 的服務資訊發給 Workload 1。

  11. Workload 1 通過 xDS 接收到 Service 2 的服務資訊。

  12. 當 Workload 1 再次發起對 Service 2 的訪問,流量會直達 Service 2(因為步驟9)。

這個方案的好處:

  • 首先不需要使用者提前配置服務間的依賴,而且服務間依賴是允許動態的增加的。

  • 最終每個 envoy 只會獲得自身需要的 xDS,效能最優。

  • 這個實現對使用者流量影響也比較小,使用者的流量不會阻塞。效能損耗也比較小,只有前幾次請求會在 Egress 做中轉,後面都是直連的。

  • 此方案對 istio 和 envoy 沒有任何入侵,我們沒有修改 istio/envoy 原始碼,使得這套方案能很好的適應未來 istio 的迭代。

目前我們只支援七層協議服務的按需載入,原因是流量在 Egress 這裡中轉的時候,Egress 需要通過七層協議裡的 header 判斷原始目的地。純 TCP 協議是沒有辦法設定額外的 header。不過因為 istio 主要目的就是為了做七層流量的治理,當網格的大部分請求都是七層的,這個情況目前可以接受的。

Lazy xDS 效能測試

測試方案

在同一網格內的不同 namespace 中,我們建立了 2 組 book info,左邊 namespace lazy-on 中 productpage 開啟按需載入,右邊 namespace lazy-off 保持預設情況。

然後在這個網格內,我們逐漸增加服務數量,使用的是 istio 官方負載測試工具集(以下簡稱「負載服務」),每個 namespace 裡有 19 個服務, 其中4個 tcp 服務,15個 http 服務,每個服務初始 pod 數目為 5,共95個 pod(75 個http,20 個tcp)。我們逐漸增加負載服務的 namespace 數量, 用於模擬網格規模增長。

效能對比

首先是 CDS 和 EDS 的對比,下圖每組資料代表負載服務 namespace 的增加,每組資料裡 4 個值:前 2 個值是開啟按需載入後的 CDS 和 EDS,後面 2個值是沒開啟按需載入的 CDS 和 EDS。

接下來是記憶體對比,綠色資料表示開啟按需載入後 envoy 的記憶體消耗,紅色的是未開啟的情況。900 pods 規模 mesh,envoy 記憶體減少 14M ,降低比例約 40%;一萬 pods 規模 mesh,envoy 記憶體減少約 150M,降低比例約 60%。

隨著服務可見性的限制,envoy 不會再接收全量的 xDS 更新,下圖是在測試周期內 envoy 接收到 CDS 更新次數的對比,開啟按需載入後,更新次數從 6 千次降低到了 1 千次。

小結

Lazy xDS 已經在 github 開源,請訪問 lazyxds README瞭解如何使用。

Lazy xDS 功能還在持續演進,未來我們將支援多叢集模式、ServiceEntry 按需載入等功能。

如果您希望瞭解更多關於 Aeraki 的內容,歡迎訪問 Github 主頁:https://github.com/aeraki-framework/aeraki

關於我們

更多關於雲原生的案例和知識,可關注同名【騰訊雲原生】公眾號~

福利:

①公眾號後臺回覆【手冊】,可獲得《騰訊雲原生路線圖手冊》&《騰訊雲原生最佳實踐》~

②公眾號後臺回覆【系列】,可獲得《15個系列100+篇超實用雲原生原創乾貨合集》,包含Kubernetes 降本增效、K8s 效能優化實踐、最佳實踐等系列。

③公眾號後臺回覆【白皮書】,可獲得《騰訊雲容器安全白皮書》&《降本之源-雲原生成本管理白皮書v1.0》

【騰訊雲原生】雲說新品、雲研新術、雲遊新活、雲賞資訊,掃碼關注同名公眾號,及時獲取更多幹貨!!

相關文章