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