快速發現和定位問題的能力是快速恢復系統的基石,只有先做到快速發現和定位問題,才能談如何解決問題,盡量減少用戶損失。那么如何在復雜的大規模場景中,做到真正的先于用戶發現和定位問題呢?我會將我們在管理大型 Kubernetes 集群過程中快速發現和定位問題的一些經驗和實踐帶給大家——我們是如何通過自研通用鏈路探測+定向巡檢工具 KubeProbe 應對遇到的大規模集群的穩定性挑戰的。
鏈路探測: 模擬廣義用戶行為,探測鏈路和系統是否異常
定向檢測: 檢查集群異常指標,發現未來存在或可能存在的風險點
系統增強: 發現問題提速增效,根因分析
發現問題之后: 后置檢查和自愈,Chat-Ops
01 業務背景和挑戰
Cloud Native
阿里云云原生應用平臺的容器服務團隊,擁有 ACK 、ASI 等產品,管理了大規模的 Kubernetes 集群,不僅向外部公有云用戶提供 Kubernetes 服務,還承擔了阿里巴巴集團上云,阿里巴巴應用全面容器化的工作。
目前,整個阿里巴巴的業務都跑在 Kubernetes 集群上并實現了云原生和容器化,例如:天貓/淘寶/高德/考拉/餓了么等等。容器服務作為阿里云的管控底座,各種云服務也運行在這些集群之上,例如視頻云/dataworks /MSE 微服務引擎/MQ 消息隊列等等。我們需要對這些基礎設施的穩定性負責。
現在,云原生的架構越來越流行,越來越多的產品和應用開始選擇云原生架構,這里有一張圖,大致示意了現代的云原生應用架構,應用生于云上,長于云上,各級提供分層的服務,這種分層的服務能夠讓業務和應用專注于業務層,屏蔽平臺和基礎設施層的復雜概念。
從穩定性的角度來講,這種應用的架構分層,上層應用的穩定性就會開始依賴底層基礎設施的支持;另外,大一統的基座既為大規模的資源調度優化和在離線混部提供場景,也對基礎設施團隊維護大規模集群的穩定性問題提出極大的挑戰。
這里有兩張形象的圖示可以展現出云原生應用架構下的業務應用和平臺層基礎設施的關系,Kubernetes 集群是非常復雜的,一個單集群的鏈路組件就有數十個甚至上百個之多,何況是大規模的多 集群管理呢? 但運行在上層 的業務同學 并不會感知到 復雜,因為我們已經把復雜包掉了,留給用戶的是一個簡單的統一接口 。 就像 淘寶這 樣的應用其實是非常復雜的,但在 用戶看 來只 是一個簡單的提交訂單而已,按鍵背后蘊含著 極其復雜的內容。 為什么做到這樣? 因為我們把復雜留給了自己,把簡單交給了用 戶。
很多時候,好的應用開發者不一定是基礎設施專家,云原生讓業務專注業務,基礎設施專注基礎設施。同時,業務很多時候也只能關心業務自身的穩定性,業務大多數時候沒有能力關心,或者是不希望投入大量的人力關心基礎設施和平臺層的穩定性,所以,關于平臺層和基礎設施的穩定性問題上,我們需要把復雜留給自己,把簡單留給用戶,為用戶提供穩定的平臺層服務。同時,更加關心全局穩定性和全局的可用性,而不是單點可用性。
容器服務是阿里巴巴集團業務以及阿里云管控/云服務的底座,上面跑著各種各樣的業務,如電商業務/中間件/二方業務/搜索/阿里云云服務等等。此外還有數百個自研和開源的組件,每年數十萬次的組件變更/數千個集群/數十萬臺節點,甚至大的集群單集群節點規模已過萬。業務架構更是紛繁復雜,有單租集群、多租集群、vc 集群、聯邦集群等等,同時還有各種在離線混布、統一調度、大促活動。在運行時也存在多種形態,如 runC,runD 等等。
因此組件的繁雜、變更頻繁、用戶場景各異、集群規模龐大、業務架構復雜……都給業務帶來了挑戰:
挑戰一:如何降低系統風險。 場景復雜,業務形態各異,任何一個不起眼細節的遺漏或環節的處置不慎都有可能導致傷害的擴大化;
挑戰二:如何對用戶集群的穩定性負責。 如何先于用戶發現和定位問題成為容器服務生產穩定性建設的重中之重,也是全局高可用體系的基石。
系統是如此的復雜,任何一個不起眼的細節遺漏或處理不慎都有可能導致非預期的傷害,我們要怎樣才能降低系統風險呢?另外我們又是如何對形態各異的用戶集群運行時全局穩定性負責的呢?如何才能先于用戶發現和定位這些集群中已經存在或即將發生的問題,是保障集群的穩定性建設的重中之重,也是 Kubernetes 全局高可用體系的基石。
02 思考和方案
Cloud Native
基于這些挑戰,我們做了一些思考和預設。下圖是一個極度簡化的用戶發布擴容鏈路,雖說極度簡化,但實際我們仍可以看出,鏈路還是比較復雜的。
為了保障這次用戶的擴容/發布鏈路暢通,我們首先帶來幾個預設:
預設 1: 鏈路復雜組件眾多,各組件分別升級迭代,數據監控無法無死角覆蓋全部場景;
預設 2: 即使鏈路中各組件/節點監控數據正常,也不能保證集群整體鏈路 100% 可用,只有經過實際業務全鏈路探測才能確定實際可用的結論;
預設 3: 反證法在證明集群不可用場景一定優于舉證法,即使 100% 監控數據正常,但只要發布失敗則證明鏈路不通。
另外,在單集群之外,我們還要關注多集群的管理,下面是一些多集群管控中的不穩定性因素示例,可以看到,多集群場景下,穩定性管控的復雜度會被放大,我們繼續帶來幾個預設:
預設 4: 在大規模集群場景下數據一致性的問題會愈加顯現,并且可能引發嚴重故障,成為一個顯著的不穩定因素;
預設 5: 集群內的監控告警鏈路存在自依賴風險,如果集群故障,則監控告警也有可能同時故障。
接下來是我們基于以上預設的一些解決方案。
探索和解決方案
1. 鏈路探測
鏈路探測即模擬廣義上的用戶行為,探測鏈路是否暢通,流程是否無異常。
想要做到先于用戶發現系統問題,我們自己首先要成為系統用戶,并且是使用最多、了解最深、無時無刻不在使用和感知系統狀態的用戶。
所謂鏈路探測,就是模擬廣義上的用戶行為,去對集群組件鏈路中的各種等待探測的對象去做探測。此處要特別說明的是,這里的用戶并不僅僅指的是狹義上使用系統的同學,而是更廣義的用戶,或者可以理解和引申成為依賴下游。
另外,在實現全鏈路探測的同時,拆解電路,實現全電路中的短路探測也是非常必要的,也是對全鏈路探測的一個補充。
2. 定向巡檢
定向巡檢是指檢查和分析大規模集群的異常指標,找到已有或將來可能存在的風險點,就像檢修管道一樣。
例如有若干個集群,它分為很多集群組,不同集群組之間的 etcd 冷/熱備是否配置齊備,風控限流配置是否正常,webhook 版本是否正常,混部參數是否一致,包括它的證書有效期是不是快要到期了等等。不同的集群組之間可能有所差別,但同類型集群之間是有一個轉衡的,因此我們可以定向做一些巡檢。
接下來是關于鏈路探測的一些常見場景:
就像一個游戲策劃,如果他連自己制作的游戲都不玩,他可能發現游戲機制的問題,把這個游戲越做越好嗎?我們要做到先于用戶發現系統問題,那我們自己首先就要先成為系統的用戶,并且一定是使用最多的,了解最深的,無時無刻不在使用和感知系統狀態的用戶。
另外,所謂鏈路探測,就是讓自己成為自己系統的用戶,模擬廣義上的“用戶”行為去對集群/組件/鏈路里的各種等待探測的對象去做探測。
一定要注意,這里的“用戶”并不僅僅指的是狹義上使用系統的同學,而是更廣義的用戶,或者可以理解引申為依賴下游。
例如業務同學要發布業務,就必然要經過 git 系統,再到發布系統,再到我們底層的基礎設施平臺,也就是我們的 ASI,這就是一次全鏈路探測流程。在這里業務同學就是用戶,探測對象可以是全鏈路。
但如果我們把 etcd 看作一個系統服務,那么 APIServer 就是它廣義上的用戶,我們模擬 APIServer 請求 etcd 這條鏈路的探測也就有了意義。
另外像 MSE 操作 zookeeper,外部用戶通過阿里云控制臺創建 ACK 集群,PaaS 平臺操作聯邦集群,甚至視頻云業務方發起一次轉碼任務,都是一樣的道理。
還有一點要關注的就是,雖然全鏈路探測看起來很美,但很多時候,全鏈路探測同時還很長,可能等到失敗的時候問題已經很大了。所以,在實現全鏈路探測的同時,拆解鏈路,實現全鏈路中的短鏈路探測也是非常必要的,也是對全鏈路探測的一個補充。
上圖是定向巡檢的場景,相比鏈路探測關注于鏈路可用性,定向巡檢的核心還是在大規模的集群場景下,數據一致性是非常困難的問題,數據不一致,將導致一些隱患,可能會在未來引發某些不確定性的故障。
所謂定向巡檢就是對整個集群或鏈路中的各項數據、指標做已知原因的檢查,找出不一致或數據偏離的點,判斷是否可能引發風險,從而做到防患于未然,治未病。
比如我們這個里邊有同一種類型的集群組,A 集群發現它的證書有效期不到三年,而其他集群的證書有效期都有三年;B 集群的 webhook 版本可能是 v2,而其他集群的 webhook 版本是 v3;C 集群的風控限流配置并沒有配一個驅逐 Pod 的限流,但其他集群都配配置了驅逐 Pod 的限流,這肯定是不符合預期的;再比如 D 集群的 etcd 的冷/熱備沒有配置或者是運行不正常,我們也可以先把它檢查出來。
03 系統實現
Cloud Native
基于上面許許多多的背景預設以及方案,我們設計并實現了一套巡檢/探測平臺,我們取名為 KubeProbe (并未開源,和現在社區上有類似命名的項目沒有任何聯系)。
我們早期也曾考慮使用社區項目 Kuberhealthy,并為 Kuberhealthy 做過一些代碼貢獻,修復過一些嚴重的代碼 Bug,最終因為功能上不太適用于我們的場景,我們選擇了自研自建。
上圖是一套中心架構,我們會有一套中心管控系統。用戶的用例會通過統一倉庫的鏡像的方式接入,使用我們通用的 sdk 庫,自定義巡檢和探測邏輯。我們會在中心管控系統上配置好集群和用例的關系配置,如某用例應該執行在哪些集群組上,并做好各種運行時配置。我們支持了周期觸發/手動觸發/事件觸發(如發布)的用例觸發方式。用例觸發后會在集群內創建一個執行巡檢/探測邏輯的 Pod,這個 Pod 里會執行各種用戶自定義的業務巡檢/探測邏輯,并在成功和失敗后通過直接回調/消息隊列的方式通知中心端。中心端會負責告警和用例資源清理的工作。
我舉一個例子,比如 Kubelet 在我們的組件運維平臺上做分批發布,每批次都會觸發一次相關集群的鏈路探測用例作為后置檢查,一旦我們發現某次發布的后置檢查失敗,我們會阻斷掉用戶的當前發布,防止傷害擴大,同時第一時間告警以及通知相關同事進入排查,是否組件新版本不符合預期。
同時,我們也支持第三方的事件回調,可以更快的集成進三方系統中。
另外,我們對于某些需要 7*24 小時不間斷的高頻次短周期探測用例,我們還實現了另外一套常駐分布式架構,這套架構使用一個集群內的 ProbeOperator 監聽 Probe Config CRD 變化,在探測 pod 中周而復始的執行探測邏輯。這套架構,完美復用了 KubeProbe 中心端提供的告警/根因分析/發布阻斷等等附加功能,同時使用了標準 Operator 的云原生架構設計,常駐體系帶來了極大的探測頻率提升(因為去掉了創建巡檢 pod 和清理數據的開銷)基本可以做到對集群的 7*24 小時無縫覆蓋,同時便于對外集成。
另外還有一個必須要提的非常重要的點,即平臺只是提供了一個平臺層的能力支持,真正這個東西要起作用,還是要看在這個平臺上構建的用例是否豐富,能不能方便的讓更多人進來寫各種巡檢和探測用例。就像測試平臺很重要,但測試用例比測試平臺更重要這個道理一樣。一些通用的 workload 探測,組件探測,固然能發現很多管控鏈路上的問題,但是更多的問題,甚至業務層的問題暴露,實際上依賴于基礎設施和業務層同學的共同努力。
從我們的實踐上來說,測試同學和業務同學貢獻了很多相關的檢查用例,比如測試同學貢獻的 ACK & ASK 的創建刪除全鏈路探測巡檢,金絲雀業務全鏈路擴容用例,比如本地生活同學的 PaaS 平臺應用檢查等等,也得到了很多穩定性上的結果和收益。目前我們維護的巡檢/探測用例有數十個,明年有機會破百,巡檢/探測次數近 3000 萬次,明年可能會過億。目前可以提前發現 99%以上的集群管控問題和隱患,效果是非常好的。
04 發現問題之后:根因分析和事件處理
Cloud Native
接下來我們聊聊發現問題之后的事情,這里有一個類似于問診對話的例子,患者發現 “哎呀我不舒服了! ” 這就是發現問題。醫生參考各種化驗單,同時做了信息聚合分析推斷,告訴患者“你已經 24 小時沒睡覺了,你睡不著是因為你很焦慮,你焦慮的根因是因為后天就要期末考試了。”這便是定位問題根因,然后針對根因去解決這個問題,他告訴患者“不要擔心,我剛收到的消息,小學生已經不需要期末考試了。”這個過程一定要快!
來自探測鏈路的告警內容往往是混沌的,和數據監控告警是有所差異的。就像上文提到的,鏈路探測告警的告警很可能就是一句患者的我不舒服了,需要你作為醫生去判斷,為什么他不舒服了呢?根因是什么。而數據監控很多時候本身就代表了原因,比如 Etcd OOM,用已有的 oncall 經驗可能得不到最好的效果。
另外快速定位問題和根因分析,是一個樹狀的搜索,經驗加工判斷的過程,也就是如何從一個混沌的表象推斷出根因,核心是邏輯。
這和健康體檢是不同的,健康體檢是列出檢查項 1,2,3,4,5......然后告訴你一堆數值。很多時候,即使存在體檢中心,我們仍然也需要醫院的專業醫生來為您解讀和判斷病情,不是嗎?
同時,根因分析/問題自愈的關鍵在于專家經驗的下沉,也就是把專家經驗下沉到系統中去,專家經驗的下沉帶來的最大收益是可復用可輸出。你可以想一下,如果我們把一個最專業的醫生的能力放進系統里,他是不是更方便的為每一個人分析病情呢?
這便是 KubeProbe 發現問題之后的全流程,我們首先會經過一個我們自建的中心化根因分析系統,在這里我們會聚合分析所有和本次失敗相關的信息,包括事件/日志/變更/告警/組件升級等等,我們將這些信息進行聚合分析,并對事件做關聯處理,最終通過一個樹狀的分析系統初步定位出某次探測失敗的原因,比如說 APIServer 超時或者 etcd 斷連等等。
此外我再補充一點,文本聯想也是一個很好的根因分析方式,我們可以通過機器學習訓練文本識別的方式來聯想出和這種失敗 case 最關聯的根因,這種 AIOps 的工作我們只是略微涉及,還在持續的探索中,我們的數據量非常大,我認為這一定是未來的方向之一。
KubeProbe 根因分析和后置處理全流程
上圖的左下方是某次我們失敗的告警,它經過根因分析系統之后發現首先最核心,最關聯,最大的原因可能是 APIserver 的連接斷開并且當前已經恢復,所以可能只是偶發的網絡抖動,我們暫時不用特別關注,但此時可以看到置信度為 90%。
另外還有一些可能的原因都會關聯起來。比如某個組件,這次探測它是由某一個組件發布出發的,它的發布人是 XXX,我們可以觀察這個發布對 API server 會產生某些影響,是否多次 list watch 不符合預期,然后把 API server list watch 出問題了,置信度有 50%。
當我們得到一個初步的原因之后,我們會進入二次確認系統做二次的原因確認,比如我們判斷原因可能是 APIServer 超時/etcd 斷聯/節點超時等,我們就會自動重新拉取一下 APIServer 接口,看一下此時是否仍然超時,是否恢復,如果恢復了,我們就普通告警,并且告訴用戶,現在沒事了,但是你得關注。如果沒恢復,那這就很嚴重了,屬于最高優先級,直接電話告警。
就是這個思路,如果有系統無法定位的問題,并且持續無法定位,我們也會觸發高級別告警,并且會增加相關的根因分析識別樹邏輯。
過多的告警等于沒有告警,我是最討厭告警海的。從經驗上講,當我們構建了一套這樣的根因分析+二次確認+后置檢查系統之后,我們的 Oncall 成本下降了 90% 以上,并且還能夠持續下降,終態可以說是無人值守,大家也可以試試類似的工作,可以說是投入小,見效大。自從這些系統建設起來以后,我們可以自豪的說,我們用很小的精力 Oncall 了每一個告警條目(對,是每一條告警,是數千個集群,數千萬次探測巡檢的每一條告警)并且不會有任何遺漏了。
最后是一些給 Oncall 人員的小甜品,Chat-ops。
基于 NLP 語義識別的 Chat-ops 系統
我們利用釘釘提供的 NLP 機器人,構建了一套比較完善的 Chat-ops 系統,這樣之后我們的 Oncall 人員就可以很方便的在告警群里通過聊天的方式操作 KubeProbe 相關功能了,比如:重跑失敗探測,查詢集群狀態,拉取診斷信息,查詢探測日志,集群告警靜默。
上圖是我們操作 Chat-ops 系統的過程。這個過程非常方便。
比如晚上我已經再被窩里了,這時候它給我了一個告警,比如某個集群之前出現了某次失敗但當前已經恢復了,需要我關注一下。
既然我關注了,我便希望某一個常用例再跑一次(它可能周期比較長,例如一個鐘頭),由于短鏈路的用例可能隨時都在跑,此時我便告訴機器人再跑一次,機器人就會識別我的語義,將集群再跑一次。跑完之后,我再通過查詢狀態看一下這個集群當前的狀態怎么樣了,這樣是非常方便的,有時候你晚上上班了,或者是在路上,或者是在被窩里,都也可以很舒服的去 on-call 一個系統了。
05 Demo 示例
Cloud Native
1、發布
2、探測列表
3、探測 Pod 開始運行
4、探測結果
5、根因分析&告警
6、Chat-ops
原文地址:https://mp.weixin.qq.com/s?__biz=MzUzNzYxNjAzMg==&mid=2247522591&idx=1&sn=4c5d02880d2b0337d78ecbb40b95cf67&utm_source=tuicool&utm_medium=referral