Categories
程式開發

螞蟻金服 Service Mesh 大規模落地系列 (Operator 篇)


本文為《螞蟻金服Service Mesh 大規模落地系列》第六篇- Operator 篇,該系列將會從核心、RPC、消息、無線網關、控制面、安全、運維、測試等模塊對Service Mesh 雙十一大規模落地實踐進行詳細解析。文末包含往期系列文章。

引言

Service Mesh 是螞蟻金服下一代技術架構的核心,也是螞蟻金服內部雙十一應用雲化的重要一環,本文主要分享在螞蟻金服當前的體量下,如何支撐應用從現有微服務體系大規模演進到Service Mesh 架構並平穩落地。本文作者:杜宏偉(花名:應明),螞蟻金服技術專家,關注 API 網關,Service Mesh 和容器網絡,螞蟻金服 Service Mesh 核心成員。

為什麼需要 Service Mesh

在此之前,SOFAStack 作為螞蟻金服微服務體系下服務治理的核心技術棧,通過提供Cloud Engine 應用容器、SOFABoot 編程框架(已開源)、SOFARPC(已開源) 等中間件,來實現服務發現和流量管控等能力。經過若干年的嚴苛金融場景的錘煉,SOFAStack 已經具備極高的可靠性和可擴展性,通過開源共建,也已形成了良好的社區生態,能夠與其他開源組件相互替換和集成。在研發迭代上,中間件類庫已經與業務解耦,不過避免不了的是,運行時兩者在同一個進程內,意味著基礎庫的升級需要推動業務方升級對應的中間件版本。

我們一直在探索更好的技術實現方式。我們發現,Service Mesh 通過將原先通過類庫形式提供的服務治理能力進行提煉和優化後,下沉到與業務進程協同,但獨立運行的Sidecar Proxy 進程中,大量的Sidecar Proxy 構成了一張規模龐大的服務網絡,為業務提供一致的,高質量的用戶體驗的同時,也實現了服務治理能力在業務無感的條件下獨立進行版本迭代的目標。

應用 Service Mesh 的挑戰

Service Mesh 帶給我們的能力很美好,但現實為我們帶來的挑戰同樣很多。比方說數據面技術選型和私有協議支持,控制面與螞蟻金服內部現有系統對接,配套監控運維體系建設,以及在調用鏈路增加兩跳的情況下如何優化請求延遲和資源使用率等等。

本文著重從 MOSN(Sidecar Proxy)的運維和風險管控方面,分享我們的實踐經驗,其他方面的挑戰及應對方案,請參考文末系列文章。

MOSN:

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

Sidecar 注入

創建注入

已經完成容器化改造,運行在 Kubernetes 中的應用,如何接入到 Service Mesh 體系中?最簡單的方式,也是以Istio 為代表的Service Mesh 社區方案所採用的方式,即是在應用發布階段,通過mutating webhook 攔截Pod 創建請求,在原始Pod Spec 的基礎上,為Pod 注入一個新的MOSN容器。

螞蟻金服 Service Mesh 大規模落地系列 (Operator 篇) 1

值得注意的是,在資源分配上,起初我們依據經驗值,在應用 8G 內存的場景下,為 Sidecar 分配 512M 內存,即

App: req=8G, limit=8G

Sidecar: req=512M, limit=512M

很快我們就發現了這種分配方案帶來的問題,一方面部分流量比較高的應用的MOSN 容器,出現了嚴重的內存不足甚至OOM;另一方面注入進去的Sidecar 容器額外向調度器申請了一部分內存資源,這部分資源脫離了業務的quota 管控。

因此,為了消除內存 OOM 風險和避免業務資源容量規劃上的偏差,我們制定了新的“共享內存”策略。在這個策略下,Sidecar 的內存 request 被置為0,不再向調度器額外申請資源;同時 limit 被設置為應用的 1/4,保障 Sidecar 在正常運行的情況下,有充足的內存可用。為了確實達到“共享”的效果,螞蟻金服sigma 團隊針對kubelet 做了調整,使之在設置Sidecar 容器cgroups limit 為應用1/4 的同時,保證整個Pod 的limit 沒有額外增加(細節這裡不展開) 。

當然,Sidecar 與應用“共享”分配到的內存資源,也導致了在異常情況(比如內存洩露)下,sidecar 跟應用搶內存資源的風險。如何應對這個風險?我們的做法是,通過擴展Pod Spec(及相應的apiserver, kubelet 鏈路),我們為Sidecar 容器額外設置了Linux oom_score_adj 這個屬性,以保障在內存耗盡的情況下,Sidecar 容器會被OOM Killer 更優先選中,以發揮sidecar 比應用能夠更快速重啟,從而更快恢復到正常服務的優勢。

此外,在CPU 資源的分配上,我們也遇到過在一些場景下,MOSN 搶占不到CPU 資源從而導致請求延遲大幅抖動,解決方案是確保在註入Sidecar 時,根據Pod 內的容器數量,為每個Sidecar 容器計算出相應的cpushare 權重,並通過工具掃描並修復全站所有未正確設置的Pod。

原地註入

在創建Pod 的時候注入Sidecar,是一件相對比較“舒服“的接入方式,因為這種做法,操作起來相對比較簡單,應用只需先擴容,再縮容,就可以逐步用帶有Sidecar 的Pod,替換掉舊的沒有Sidecar 的Pod。可問題是,在大量應用,大規模接入的時候,需要集群有較大的資源 buffer 來供應用實例進行滾動替換,否則替換過程將變得十分艱難且漫長。而螞蟻金服走向雲原生的目標之一則是,雙十一大促不加機器,提高機器使用率。如果說我們要花更多的錢購買更多的機器來支持雲原生,就多少有點事與願違了。

為了解決這個問題,我們提出了“原地註入”的概念,也就是說在 Pod 不銷毀,不重建的情況下,原地把 Sidecar 注入進去。

螞蟻金服 Service Mesh 大規模落地系列 (Operator 篇) 2

如圖所示,原地註入由以下步驟構成:

  • 在 PaaS 提交工單,選擇一批需要原地註入的 Pod;
  • PaaS 調用中間件接口,關閉業務流量並停止應用容器;
  • PaaS 以 annotation 的形式打開 Pod 上的原地註入開關;
  • Operator 觀察到 Pod 原地註入開關打開,渲染 sidecar 模版,注入到 Pod 中並調整 cpu/memory 等參數;
  • Operator 將 Pod 內容器期望狀態置為運行;
  • kubelet 將 Pod 內容器重新拉起;
  • PaaS 調用中間件接口,打開業務流量;

Sidecar 升級

我們將 RPC 等能力從基礎庫下沉到 Sidecar 之後,基礎庫升級與業務綁定的問題雖然消除了,但是這部分能力的迭代需求依然存在,只是從升級基礎庫變成瞭如何升級 Sidecar。

最簡單的升級就是替換,即銷毀 Pod 重新創建出一個新的,這樣新建出來的 Pod 所注入的 Sidecar 自然就是新版本了。但通過替換的升級方式,與創建注入存在相似的問題,就是需要大量的資源 buffer,並且,這種升級方式對業務的影響最大,也最慢。

非平滑升級

為了避免銷毀重建 Pod,我們通過 Operator 實現了“非平滑升級”能力。

螞蟻金服 Service Mesh 大規模落地系列 (Operator 篇) 3

如圖所示,非平滑升級需要:

  • PaaS 關流量,停容器;
  • Operator 替換 MOSN 容器為新版本,重新拉起容器;
  • PaaS 重新打開流量;

可以想到,原地升級Pod 打破了Kubernetes immutable infrastructure 的設計,為了能夠實現我們的目標,sigma 團隊修改了apiserver validation 和admission 相關的邏輯以允許修改運行中的Pod Spec,也修改了kubelet 的執行邏輯以實現容器的增刪啟停操作。

平滑升級

為了進一步降低 Sidecar 升級對應用帶來的影響,我們針對 MOSN Sidecar 開發了“平滑升級”能力,以做到在 Pod 不重建,流量不關停,應用無感知的條件下對 MOSN 進行版本升級。

螞蟻金服 Service Mesh 大規模落地系列 (Operator 篇) 4

從上圖可見,Operator 通過注入新 MOSN,等待 MOSN 自身進行連接和 Metrics 數據的遷移完成,再停止並移除舊 MOSN,來達到應用無感,流量無損的效果。整個過程看似沒有很複雜,實則在各個環節上充斥著各種細節上的配合,目前為止,在平滑升級能力上,我們仍需在成功率方面努力,也需要改進Operator 的狀態機來提升性能。關於 MOSN 自身的連接遷移過程,讀者如有興趣,可參閱系列分享中的對應篇章。

Sidecar 回滾

為了確保大促活動萬無一失,我們還提供了Sidecar 回滾的保底方案,以備在識別到Service Mesh 出現嚴重問題的情況下,迅速將應用回滾到未接入Sidecar 的狀態,使用應用原先的能力繼續提供業務服務。

風險管控

從技術風險角度來看,關於 Sidecar 的所有運維操作,都要具備三板斧能力。在灰度能力上,Operator 為升級等運維動作增加了顯式的開關,確保每個執行動作符合用戶(SRE)的期望,避免不受控制地,“偷偷地“自動執行變更操作。

監控方面,在基本的操作成功率統計、操作耗時統計、資源消耗等指標之外,仍需以快速發現問題、快速止血為目標,繼續完善精細化監控。

Operator 目前對外提供的幾個運維能力,細節上都比較複雜,一旦出錯,影響面又很大,因此單元測試覆蓋率和集成測試場景覆蓋率,也會是後續Service Mesh 穩定性建設的一個重要的點去努力完善。

未來的思考

演進到 Service Mesh 架構後,保障 Sidecar 自身能夠快速,穩定的迭代十分重要。相信在未來,除了繼續增強 Operator 的能力,也需要通過以下幾個可能的優化手段,來做到更好的風險控制:

  • 對 Sidecar 模版做版本控制,由 Service Mesh 控制面,而非用戶來決定某個集群下某個應用的某個 Pod 應該使用哪個版本的 Sidecar。這樣既可以統一管控全站的 Sidecar 運行版本,又可以將 Sidecar 二進制和其 container 模版相綁定,避免出現意外的,不兼容的升級。
  • 提供更加豐富的模版函數,在保持靈活性的同時,簡化 Sidecar 模版的編寫複雜度,降低出錯率。
  • 設計更完善的灰度機制,在 Operator 出現異常後,快速熔斷,避免故障範圍擴大。
  • 持續思考,整個 Sidecar 的運維方式能否更加“雲原生”?

最後

雙十一的考驗強化了我們在雲原生道路上探索的信心,未來還有很長的路要走,任重而道遠。期望我們能夠與更多感興趣的同學交流,一起建設 Service Mesh 技術體系,繼續用技術幫助業務更好發展。

SOFAStack 部分開源項目地址

SOFABoot:

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

SOFARPC:

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

本文轉載自公眾號金融級分佈式架構(ID:Antfin_SOFA)。

原文鏈接

https://mp.weixin.qq.com/s/zyRSzj9uo9TZ58caWdTH9A