本文爲《螞蟻金服 Service Mesh 大規模落地系列》第六篇 - Operator 篇,該系列將會從核心、RPC、消息、無線網關、控制面、安全、運維、測試等模塊對 Service Mesh 雙十一大規模落地實踐進行詳細解析。文末包含往期系列文章。git
Service Mesh 是螞蟻金服下一代技術架構的核心,也是螞蟻金服內部雙十一應用雲化的重要一環,本文主要分享在螞蟻金服當前的體量下,如何支撐應用從現有微服務體系大規模演進到 Service Mesh 架構並平穩落地。github
本文做者:杜宏偉(花名:應明),螞蟻金服技術專家,關注 API 網關,Service Mesh 和容器網絡,螞蟻金服 Service Mesh 核心成員。web
在此以前,SOFAStack 做爲螞蟻金服微服務體系下服務治理的核心技術棧,經過提供 Cloud Engine 應用容器、SOFABoot 編程框架(已開源)、SOFARPC(已開源) 等中間件,來實現服務發現和流量管控等能力。通過若干年的嚴苛金融場景的錘鍊,SOFAStack 已經具有極高的可靠性和可擴展性,經過開源共建,也已造成了良好的社區生態,可以與其餘開源組件相互替換和集成。在研發迭代上,中間件類庫已經與業務解耦,不過避免不了的是,運行時二者在同一個進程內,意味着基礎庫的升級須要推進業務方升級對應的中間件版本。編程
咱們一直在探索更好的技術實現方式。咱們發現,Service Mesh 經過將原先經過類庫形式提供的服務治理能力進行提煉和優化後,下沉到與業務進程協同,但獨立運行的 Sidecar Proxy 進程中,大量的 Sidecar Proxy 構成了一張規模龐大的服務網絡,爲業務提供一致的,高質量的用戶體驗的同時,也實現了服務治理能力在業務無感的條件下獨立進行版本迭代的目標。api
Service Mesh 帶給咱們的能力很美好,但現實爲咱們帶來的挑戰一樣不少。比方說數據面技術選型和私有協議支持,控制面與螞蟻金服內部現有系統對接,配套監控運維體系建設,以及在調用鏈路增長兩跳的狀況下如何優化請求延遲和資源使用率等等。安全
本文着重從 MOSN(Sidecar Proxy)的運維和風險管控方面,分享咱們的實踐經驗,其餘方面的挑戰及應對方案,請參考系列分享中的其餘文章。網絡
MOSN:https://github.com/sofastack/sofa-mosn架構
已經完成容器化改造,運行在 Kubernetes 中的應用,如何接入到 Service Mesh 體系中?最簡單的方式,也是以 Istio 爲表明的 Service Mesh 社區方案所採用的方式,便是在應用發佈階段,經過 mutating webhook 攔截 Pod 建立請求,在原始 Pod Spec 的基礎上,爲 Pod 注入一個新的 MOSN 容器。app
值得注意的是,在資源分配上,起初咱們依據經驗值,在應用 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 注入進去。
如圖所示,原地注入由如下步驟構成:
在 PaaS 提交工單,選擇一批須要原地注入的 Pod;
PaaS 調用中間件接口,關閉業務流量並中止應用容器;
PaaS 以 annotation 的形式打開 Pod 上的原地注入開關;
Operator 觀察到 Pod 原地注入開關打開,渲染 sidecar 模版,注入到 Pod 中並調整 cpu/memory 等參數;
Operator 將 Pod 內容器指望狀態置爲運行;
kubelet 將 Pod 內容器從新拉起;
PaaS 調用中間件接口,打開業務流量;
咱們將 RPC 等能力從基礎庫下沉到 Sidecar 以後,基礎庫升級與業務綁定的問題雖然消除了,可是這部分能力的迭代需求依然存在,只是從升級基礎庫變成了如何升級 Sidecar。
最簡單的升級就是替換,即銷燬 Pod 從新建立出一個新的,這樣新建出來的 Pod 所注入的 Sidecar 天然就是新版本了。但經過替換的升級方式,與建立注入存在類似的問題,就是須要大量的資源 buffer,而且,這種升級方式對業務的影響最大,也最慢。
爲了不銷燬重建 Pod,咱們經過 Operator 實現了「非平滑升級」能力。
如圖所示,非平滑升級須要:
PaaS 關流量,停容器;
Operator 替換 MOSN 容器爲新版本,從新拉起容器;
PaaS 從新打開流量;
能夠想到,原地升級 Pod 打破了 Kubernetes immutable infrastructure 的設計,爲了可以實現咱們的目標,sigma 團隊修改了 apiserver validation 和 admission 相關的邏輯以容許修改運行中的 Pod Spec,也修改了 kubelet 的執行邏輯以實現容器的增刪啓停操做。
爲了進一步下降 Sidecar 升級對應用帶來的影響,咱們針對 MOSN Sidecar 開發了「平滑升級」能力,以作到在 Pod 不重建,流量不關停,應用無感知的條件下對 MOSN 進行版本升級。
從上圖可見,Operator 經過注入新 MOSN,等待 MOSN 自身進行鏈接和 Metrics 數據的遷移完成,再中止並移除舊 MOSN,來達到應用無感,流量無損的效果。整個過程看似沒有很複雜,實則在各個環節上充斥着各類細節上的配合,目前爲止,在平滑升級能力上,咱們仍需在成功率方面努力,也須要改進 Operator 的狀態機來提高性能。關於 MOSN 自身的鏈接遷移過程,讀者若有興趣,可參閱系列分享中的對應篇章。
爲了確保大促活動萬無一失,咱們還提供了 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
Service Mesh Meetup 第9期來啦,本期與滴滴聯合舉辦,將深刻 Service Mesh 的落地實踐,並帶領你們探索 Service Mesh 在更廣闊領域的應用。歡迎參加~
主題:Service Mesh Meetup#9 杭州站:To Infinity and Beyond
時間:2019年12月28日13:00-17:30
地點:杭州西湖區紫霞路西溪谷G座8樓
報名方式:點擊「這裏」,便可報名