輕松應對上千節點失效,去哪兒網混沌工程自動演練實踐
?一、混沌工程價值探討
因為混沌工程是一個比較新興的技術,所以不可避免地會面臨一個問題:當我們要落地混沌工程時,需要對其進行價值的論證,再決定我們需要投入的人力,以及期望達到的效果。
作為技術行業的從業者,我們經常會了解到各大公司出現的宕機的情況,比如去年韓國電信網絡的崩潰,以及Facebook服務器宕機的事件,國內各大廠商尤其是云廠商其實都會出現大規模的宕機故障。大部分人看到這些新聞都是吃瓜心態,但是作為技術行業的從業者,這類問題也許某一天就會發生在我們身上,出現在我們的機房和公司里,并且需要我們去解決。
?1、去哪兒網的系統群情況
接下來我簡單介紹去哪兒網的系統群情況。目前線上運行的活躍的應用有3000+個,提供18000+個dubbo rpc的服務接口,有3500+個http的域名注冊,有13000+個mq的主題,公司內部有5種語言的技術棧,以Java和node為主,可見其中關系的復雜程度。只要一個地方出現問題,就有可能會級聯地傳遞到c端,那么用戶側就會感受到問題。因此我們應該如何治理這些系統群?混沌工程則是一個非常好的手段,后面我將會介紹如何用混沌工程解決這些問題。
?2、常見故障原因
在我從業的八九年期間,我們也遇見過大量的基礎設施問題,如微服務的注冊中心zookeeper經常出現抖動的問題,消息隊列出現問題,甚至機房的網絡、斷電也會出現問題。
從故障的原因來看,我們可以將其分成幾大類:
底層的機房、中間件、機器問題影響規模相對較大,機房掛掉時整個機房的相關應用都會受到影響;
- 上層有應用問題,以及整個拓撲里都會有依賴問題。
不同故障的原因千差萬別,只有拉長時間線才能夠發現其中存在著一定的共性,但是短期內很難通過方法解決一切問題,混沌工程則能夠很好地使其從被動轉成主動的形式。
混沌工程主要解決的問題并不是讓軟件不失敗,而是軟件在失敗的情況下是否還有一定的韌性,是否還能提供高質量的服務,以及能否主動構建失敗并提前將其修復。因此我認為混沌工程的目標有兩個:
- 一是通過混沌工程,我們可以建立對系統抵御生產環境中失控條件的能力和信心,這需要我們提前處理問題,并產生對應的改進和預案。
- 二是把不確定的東西變確定,實際上無論是質量還是可靠性、穩定性,最可怕的并不是我們能否做什么,而是我們永遠不知道我們做完之后是否還有問題。
?3、混沌工程的收益
我認為混沌工程可以有以下三方面的收益。
1)人
人的不同角色,如從用戶的角度來看,能夠得到穩定的用戶體驗,不會再由于技術問題導致用戶體驗的不佳,甚至于無法得到服務;從測試的角度來看,能夠提前降低甚至有可能阻止故障的發生;從開發和運維的角度來看,可以提升應急的效率。
2)流程
把一個亂序的具體問題具體分析的流程轉化為體系性治理的流程。
3)系統
面向正確的設計轉向了面向失敗的設計,為整個系統提供了一定的韌性容災能力。對于一些基礎能力而言,可觀測、可灰度、可回滾、可降級都不再是期望,而是實際能夠得到的能力。
二、去哪兒網混沌工程平臺
我們首先提出一個問題:混沌工程的最佳實踐到底是什么?
在業界里大家經常看到的混沌工程,第一反應就是攻防演練,如線上隨機地插拔、隨機地注入故障,而我個人并不是很認同?;煦绻こ淌前巡淮_定的問題變成確定的,雖然人的攻防也可以一定程度上解決這個問題,但是人的攻防需要投入的時間非常多,而且攻防產生的知識,能夠固化、擴展的幅度也是有限的,除非能夠把混沌工程的文化在全公司里從上到下執行得非常徹底。
從這個角度來看,隨機演練不是我們的最終目標,那我們的目標到底是什么?
我認為需要分成多階段的目標,待會我會按照我們的實踐路線進行講解。需要注意的是,功能支持并不等于實踐模型。目前很多公司在做混沌工程相關的系統,或者在提供同樣的能力。但我認為其中存在很大的偏差,在于提供了能力并不代表達到了混沌工程的目標。因為從實踐模型來看,覆蓋面、有效率如何,接下來我會具體講解我們的實踐。
從應用架構層次來看,基本每個公司偏差不大,最底層是機房可用區,往上依次是中間件、服務器層、應用層、依賴層。層次越往下,出問題的概率相對而言越小。在服務治理里超時熔斷甚至限流發生頻率非常高,但是在機房層面統一的掛掉或斷電的概率則小很多。然而,底層的失效概率小,影響面卻非常大。應用架構的層次和對應的失效情況,很大程度影響了我們實踐的節奏。
混沌工程要達到兩個目標,并不是一蹴而就的,這意味著我們要做大量的工作以確保機制的制定和生效。應用架構層次是我們對應階段劃分投入的人力時一個很好的向導。當我們一無所有時,應當優先解決影響面大的問題。如果把服務之間依賴關系做得很好,但機房掛掉或中間件掛掉了,整個服務都不可用時,一切都是笑談。
因此,從實踐路徑出發,我認為可以分成四個節奏:
1)先要做到機房、中間件、實體機、虛擬機級別的關機演練,盡可能消除大面的影響。
2)應用演練在于應用的可用性治理。
3)依賴演練在于拓撲合理性依賴的治理。
4)攻防演練解決的是人面對失效時,是否有對應的預案策略,預案策略的執行時效性與恢復時間。
從左往右的路徑其實是一個影響面逐漸縮小的過程。
?1、關機演練
去哪兒網的混沌工程平臺建設第一步就是關機演練的支持。能力目標上,我們要求同一機房某業務線所有服務節點掛掉時不受影響,那么我們單次演練可能需要有上千臺節點的失效。要達到這樣的能力,需要直接利用混沌工程現代化的技術并不多,因為關機演練不是針對應用級別,而是針對機器節點級別,它的關鍵點在于基礎信息的整合和整個流程的打通。
1)機房聚合信息查詢
能夠發現應用是否符合標準,即當機房掛掉時,應用是否受到影響。其中有兩個方面的影響,一是應用只在單機房部署,二是單機房掛掉的情況下它的容量是否足夠,從而對應用提前進行改造。
2)自動建立溝通群
如果整個執行周期非常久,我們需要提前制定計劃,將非常明顯的問題進行改造,再進行真正執行的進度周知,以及事后的總結。以上過程都需要大量自動化信息的周知,我們在內部的IM體系上有一套溝通和通知機制的方式。
3)真實關機
測試機器重啟和應用重啟的時間是否滿足要求,如果只是做一個假的失效,演練的恢復速度快并不意味著真正的故障發生時速度也足夠快。
4)接入告警,告警事件關聯推送
5)虛擬機開機后關聯服務自動恢復
我們的能力目標需要大量的節點失效,因此我們無法人工進行恢復,當機房真正出現問題時我們也不可能依靠人工逐個應用排查和恢復,因此虛擬機開機后關聯服務自動恢復的功能非常關鍵。
關機演練的實現有以下幾點:
- 控制維度:我們提供了機房、應用、機器三種級別的篩選。
- 技術角度:沒有涉及到現在的chaosmesh或chaosblade等技術,更多運用一些云集群的原生技術,如openstack的API或saltstack,以及一個我們自研的控制面,包含了我們剛才提到的控制、演練、編排的功能。
關機演練效果:
- 我們執行了49次機房演練,覆蓋的機器去重完之后共有4000+個機器,覆蓋了500+個應用,每次演練基本上能發現10+個問題。
- 針對單機器級別的關機演練,我們執行了71次,覆蓋了3000+個機器和200+個應用。
當我們執行真正的關機演練時,如果監控圖出現異常情況,就代表機房有問題會影響C端的業務,那么我們就需要將其提前修復。主動發現問題,則能制定對應的修復計劃,提前修復問題。
?2、應用演練
應用演練的能力目標是對所有應用都可以選擇多策略的故障注入,主要解決應用可用性的問題。關鍵點在于:
1)要在線上環境做單應用的可用性演練
因為線上環境與測試環境、演練環境存在區別,包括服務治理的參數和對應的配置,進而服務產生的應對現象也是不同的。如果在測試環境做得很好,線上環境由于配置不同,也很可能導致演練得到的結果是錯誤的。
2)可靠的注入工具
因為我們要對非常核心的應用做失效情況的注入,可靠的工具對我們而言是一個生命線,如果注入工具本身不可靠,很可能會級聯帶來很多問題。
3)豐富的演練策略
4)生效面要可控
不能因為演練導致無差別的攻擊,導致線上出問題。
首先要對注入工具做技術選型。我們云平臺里的容器和虛擬機都需要支持,要求的場景也比較豐富,我們對開源的要求也比較高,因為需要進行二次開發,最終從選型上我們選擇了比較適合的chaosblade。
接下來對chaosblade做一個簡單的介紹。
chaosblade支持的場景非常多,有容器級別、操作系統級別以及語言層面的,比如Java的executor。以上是我們廣泛應用的,尤其是通過Java的技術,我們對其進行了大量的改造。
chaosblade的功能基本上涵蓋了我們日常通用的中間件場景,比如在應用服務的層次里,一般的rpc框架、網關、消息中心件對于我們來說覆蓋面是比較廣的,特別是數據庫、緩存等都有一定的支持。
chaosblade基礎功能比較完善,但是在企業場景里有一些缺失,比如HTTP超時能力、fullGC和日志擁堵,甚至官方不支持同一個接口的依賴但是不同的調用點等區分,以及比如全鏈路的匹配。我們把這些能力實現之后回饋給了官方,因此大家現在再去用最新版本的chaosblade則具備了以上企業場景。
選完chaosblade之后,我們需要進行演練前的準備,首先選定它的資源和策略,在演練進行的過程中把 agent自動化掛載上去,再通過選好的策略自動注入故障,通過流量copy的方式和人工手動觸發的case在C端觸發兩部分進行驗證。目前我們已經實現了全鏈路的場景匹配,因此能夠區分用戶的真實流量和測試人員的人工流量。在恢復階段我們有兩種恢復方式,一是對我們來說是預防底線的告警或超時恢復,如果都執行完之后沒有觸發則采取人工恢復,然后卸載agent,最后總結問題并改進完成復盤。
以上是新建演練效果圖,演練時可以選擇對應的應用、機器以及策略,編排好之后就可以定期執行。
?3、依賴演練
應用可靠性不僅受應用本身影響,還會受到依賴的信息服務影響。大家維護所有應用時都會想到:死道友不死貧道,即所有的同行都可以出現問題但我不能。當我們保持這個心態治理服務時,就需要非常關注依賴關系,被拖死、被波及、被傳遞時,如何解決依賴關系導致的蝴蝶效應;依賴的超時、熔斷、異常、限流是否符合我們的預期;以及強依賴太多,能否降級為弱依賴,以上問題都非常關鍵。
因此,依賴演練的能力目標是對應用層的外部依賴進行多策略演練,并且斷言它是強依賴還是弱依賴。依賴演練的關鍵點在于:
1)做好應用元數據采集
如果沒有應用元數據的采集,則無法得知應用所有的外部依賴。我們將所有rpc和服務注冊相關的、數據依賴和redis以及一些定時任務等信息采集到一起,將通過日志、注冊中心、DB元數據或應用暴露出來的元數據,甚至還有trace信息進行匯總,產生了一個最全的應用元數據。
2)可視化應用拓撲結構
便于我們觀測到該應用被誰調了,我調了誰,對于我們做生效面控制非常有效。
3)區分不同場景的同一個依賴
即剛才提到的不同調用點的同一個接口的依賴。
4)標注強弱依賴關系
將采集到的信息進行分析聚合和存儲,并對信息進行強弱依賴關系標注。以上是強弱依賴關系標注的界面效果圖,我們能夠區分的類型多且細,對應的目標也非常多。
依賴演練存在一個邏輯的閉環:當我們的服務治理收集了依賴關系之后,需要讓用戶標注依賴關系,相當于得知用戶期望的依賴,我們再進行強弱依賴演練,并且得到演練結果進行修正,查看是否符合用戶預期,從而產生對比差距。如用戶期望它是一個弱依賴,實際線上執行它是一個強依賴,那么就能產生我們改進的計劃集,對其進行修復。
依賴演練效果:
我們執行了1200+次演練,依賴的接口涉及3000+個,我們在去年五一前做的依賴演練發現了136個問題,且問題類型各不一致,如代碼編寫將一個弱依賴寫成了一個強依賴,以及配置問題、容量問題等。
?4、平臺架構
關機演練、應用演練與依賴演練做完之后,我們平臺架構如上圖。
- 下面的資源層我們支持三種形態:實體機、虛擬機、容器,不同的操作有不同的手段。
- 演練系統里我們也有較為豐富的功能:演練生成、演練編排,以及對應的執行、標注等。
- 上面是應用管理平臺和依賴信息平臺,還有一些監控等APM之類的支持。
三、大規模自動演練
雖然我們已經具備了大規模自動演練對應的能力,但是當我們想要做到非常大覆蓋面的演練時,我們需要思考一個問題:常態化演練的成本收益比是否合理?
如果只是節假日演練或者一年演練一兩次,那么就需要權衡投入。當我們常態化演練時,不可避免地要考慮人工成本,正如我前面提到的演練次數里,都需要人工進行一定的參與,那么就會耗費一些人工成本。當我們常態化之后就要考慮自動化,能做到自動化就能替換人工成本。
此外,質量類工作的性價比天然要求更高,因為質量類工作不像創造性工作,防御型工作要求覆蓋面全,如果在每個點上的性價比不夠高,那么全局損耗就會非常大,這對我們來說是一個非常好的指導。
自動化要達到一個目標,就是持續可靠,我們要使其常態化地運行和自動地演練,主要涉及到兩個點:
- 一是我們希望它常用常新,減少人工成本,并且把覆蓋面提升到最大。
其中的關鍵點在于它自動化執行的流量和斷言。人工參與的目的就是斷言最后結果和制定具體的計劃。
- 二是可用的環境。
我們將周期性自動演練的機制分成兩類:
- 增量演練,每天把新增的依賴全部演練一遍。
- 全量演練,設定周期重復執行。
因為我們所有的代碼和架構都在腐化的過程中,中間會有很多變更,比如調用點的代碼變更,則有可能導致強弱依賴的關系被轉化,因此我們必須周期性地進行驗證。
?1、自動演練流程
我們自動演練的流程如上圖。
第一步是做控制面,可以獲取到應用的信息。
第二步是對其進行故障的注入。
第三步是觸發自動化測試,從而產生兩份流量,這兩份流量會打向我們的基準環境和對應測試環境,測試環境的代碼配置等與基準環境是相同的,然后自動化平臺會對兩者返回的結果做一個斷言,進而得到一個結論:當我注入這個問題時,流量是否依然正常。自動化檢測完結果之后就能產生依賴關系的判斷。如果注入了故障從而產生了問題,那就意味著它是個強依賴。
通過自動演練流程,引入了自動化測試平臺之后,我們就能做到不需要人工觸發流量和判斷。
?2、演練結論
從效果數據上看,不符合開發預期的依賴非常多,遠超大家的想象,在抽樣中達到了73%,而符合預期的只占了27%。主要問題有不合理的強依賴、單應用演練口徑過嚴、自動化測試平臺覆蓋不足、無法完全線上化等。
如果是單應用通過接口自動化平臺做斷言,可能會產生一個問題,就是結論可能過嚴。比如A依賴了B再依賴C,對于 B調C,可能是一個強依賴,但它并不會傳導到用戶端,對用戶側可能是沒有影響的,只是一個局部的強依賴,那么就會放大這個問題。
因此我們考慮是否可以全鏈路進行演練,經過試驗是可行的。
?3、全鏈路演練
從信息來看,一個功能入口對應后面的一個過程,過程里的強弱依賴關系是非常復雜的,可能有一條完整的強依賴,也可能有中間部分的強依賴,或者一些是純弱依賴,這些關系決定了我們的方案。
與剛才說的單應用斷言不同,做全鏈路斷言需要引入一個全鏈路壓測的演練系統。我們內部有一個全鏈路壓測平臺,能夠做到用例自動生成、數據隔離,且執行成本非常低,比如執行完一個機票業務線所有核心場景可能只需要半天,相當于我們只需要0.5pd的人力就能覆蓋上千個應用。
從斷言來看,我們有一個斷言的邏輯:當入口產生調用流量時,我們就會對它進行一個斷言,觀測我們的核心指標尤其是用戶側的核心指標是否存在問題,如果存在問題,我們則會中斷演練,并且記錄對應的結果;如果不產生對應的報警,我們還會從另外一個角度看是否對C端的功能有其它影響。我們會對人工主動標注的告警事件和系統自動分析的雷達事件進行統一,進而得到一個結論,就是當全鏈路注入問題時,對于入口來說是一個強依賴還是一個弱依賴,這是斷言的邏輯。
從流程來看,與剛才的自動演練流程有點相似,只是把接口自動化的測試平臺轉化為全鏈路壓測平臺,但是它的斷言與自動化的斷言邏輯不同。
需要注意的是,我們需要對鏈路上的命中率做一定的優化。
命中率是指從入口發下去的流量是否一定會經過我們想測試的依賴,比如我想測e系統打到g系統的調用,入口的流量發出來不一定都能達到e的依賴鏈路里,它打到了b系統,再打到e系統,再打到了f系統,這就需要一個非常有效的機制提前發現,演練的流量與我們預期的依賴是否達到。這需要依賴到其它大量的信息,如果我們沒用精準的方式,而是隨機地挑選入口流量,那么鏈路上的命中率只有40%左右,我們希望能夠將命中率提到90%以上。
我們針對命中率做了一個精準的策略:利用依賴關系已經產生的實際數據,即線上APM的trace數據反查能夠經過鏈路的請求條件和流量,比如當我們想要找e和f的調用鏈路時,可以從b系統入口打到e系統再打到f系統,這就是我們想要找的其中一個鏈路,再逆向給出一個結論,從而得到對應trace的入口信息,再得到入口的請求條件信息,通過請求條件做用例的自動構造,就能得到一部分非常有效的用例,從而把我們的命中率提升到了90%以上。
從全鏈路自動演練的效果來看,目前覆蓋了去哪兒網的55個核心入口和80%以上的核心應用,僅剩最后的人工成本,只要對匯總的報告進行最終的分析,產生一個節假日混沌工程的報告即可。
四、故障注入攻防演練
第四個階段是故障注入攻防演練。攻防演練的主要目的在于提升人面向失效條件時的處理速度,包括預案和問題。
- 首先通過各個系統的開發處理失效條件很難積累經驗。
因為一個開發真正能遇到線上故障的概率并不高,公司成百上千人的研發團隊會對故障進行稀釋,因此人為的經驗很難積累,那么我們只能提前創造機會,當他真正面臨線上問題時才能給出解決方案。
- 二是故障原因種類繁多。
- 三是沒有預案。
- 四是恢復和驗證比較困難。
2020年,我們故障處理時間的中位數是54分鐘和39分鐘,2021年也是51分鐘,因此在線上的真實故障里處理的時間還是比較長的。
?1、攻防演練流程
我們設計了一個攻防演練的流程:
流程依賴于大量的基礎設施系統,包含故障平臺、混沌工程平臺、監控告警平臺、日志平臺、trace平臺等。首先做攻擊點的規劃,匯總歷史故障原因,優先把出現次數多的原因規劃為對應的攻擊點;其次故障隨機注入,注入點與時間隨機,不同的接口依賴不提前告知開發;然后監控告警觸發,防守方排查問題,需要上報對應的結論、耗時等排查結果;最后對其進行一定的計分公式,復盤分析。
故障注入流程與全鏈路依賴流程相似,只需要把流量真正注入即可,不需要斷言它的強弱依賴。
從積分例子可以看出,大部分問題1~3分鐘即可解決,通過這個方式演練能夠有效提升排查和處理問題的速度。
?2、攻防演練的關鍵點
1)培養混沌文化
混沌工程要做對應的宣導,開發對于攻防演練是非常關心的。
2)時間和策略隨機
3)抹除信息干擾
比如不能在異常棧里暴露注入的信息,不能出現chaosblade等對應的關鍵字,以及一些流量標識也需要抹除。
Q&A
Q1:如何確定應用級災備的演練和驗證范圍?
A1:應用級的災備需要多可用區,確保每個應用不能只部署在一個可用區,在信息聚合時可以提前發現并改造。改造后真實演練就是分享中提到的機房大規模關機演練,從云平臺元信息中能夠方便地查詢出某業務線所有應用實例,然后進行真實關機演練。觀測對應的核心業務指標,如果業務正常,說明災備、容量的情況滿足。對于驗證范圍,單應用的演練只需要在當前應用接口級別測試即可,方式可以多種,比如接口自動化測試、人工觸發用例測試。
Q2:越底層的故障影響越大,請問您有沒有用混沌工程做過底層的網絡故障?
A2:底層網絡故障我們主要通過大規模關機演練替代,因為在交換機和機器上的網絡通信失敗并不是很可怕的事情,在問題點上恢復后影響基本也就自動恢復了。如果實在有必要演練網絡問題,可以進行交換機拔線測試。
Q3:混沌工程在推進過程中,如何衡量業務層面的需求?
A3:業務層面需要區分不同角色:對于業務負責人來說,混沌工程的結果需要利于業務,比如保證用戶體驗、保障業務平穩運行;對于技術負責人來說,混沌工程能夠提升人員處理線上問題的速度;對于穩定性保障人員,例如QA,混沌工程能夠讓不確定性轉化為高確定性。此外,如果問題中的需求是指混沌工程推進跟業務項目有人力沖突,可以參考分享中的實踐路徑,機房關機演練、應用演練、依賴演練其實并不太多的人力資源,攻防演練則需要給業務需求項目讓步。
Q4:關鍵系統的混沌工程實驗思路有何不同?
A4:在我們實踐過程中,關鍵系統并沒有特殊對待,一切都要追求高效和高覆蓋。對于關鍵系統也是真實關機、真實注入、真實線上環境。?