字節(jié)跳動混沌工程實踐總結(jié) | IDCF

內(nèi)容來源:字節(jié)跳動技術(shù)團隊 作者:基礎(chǔ)架構(gòu)團隊?

(圖片來源于網(wǎng)絡(luò))
本文選自“字節(jié)跳動基礎(chǔ)架構(gòu)實踐”系列文章。 混沌工程是通過故障注入的方式幫助系統(tǒng)尋找薄弱點,從而提高系統(tǒng)的穩(wěn)定性。隨著微服務(wù)、云原生相關(guān)技術(shù)的發(fā)展,分布式系統(tǒng)已經(jīng)流行在業(yè)界各處,但因此也帶來了復(fù)雜度急劇上升、故障發(fā)生難以預(yù)測后果、難以避免與驗證等挑戰(zhàn)。而混沌工程正是通過故障注入等方式為切入點,幫助解決以上問題。本文討論了字節(jié)跳動引入混沌工程以來的相關(guān)實踐,希望能提供一些參考。
一、背景:什么是混沌工程
二、業(yè)內(nèi)實踐
Netflix 最早系統(tǒng)化地提出了混沌工程的概念,并出版了混沌工程領(lǐng)域內(nèi)的首部書籍《混沌工程:Netflix 系統(tǒng)穩(wěn)定性之道》[1],在本書中提出了混沌工程成熟度模型與應(yīng)用度模型,并總結(jié)了五條高級原則,對于混沌工程的發(fā)展具有指導(dǎo)性意義。另外 Netflix 開源了其混沌工程項目 - Chaos Monkey[3]。 阿里巴巴是國內(nèi)較早開始探索混沌工程并做出開源的公司,其開源項目 ChaosBlade[4]可以結(jié)合阿里云進行 chaos 實驗。 PingCap 作為國內(nèi)優(yōu)秀的數(shù)據(jù)庫領(lǐng)域開源公司,其在混沌工程領(lǐng)域一直有投入,并在最近開源了內(nèi)部混沌工程實踐平臺 - Chaos Mesh[5]。 Gremlin 為一家混沌工程商業(yè)化公司,該公司提供了一個混沌工程實驗平臺,通過將其 agent 安裝在云主機上觸發(fā)故障。同時提出了 chaos gameday[2] 的概念。
三、字節(jié)跳動如何實踐
故障注入 自動化指標分析 活動實踐落地
降低實驗的時間成本,我們可以依賴自動化指標分析,幫助我們進行輔助判斷,從而尋找更大的產(chǎn)出。 降低實驗的風(fēng)險成本,我們可以依賴自動化指標分析,進行穩(wěn)定性判斷,作為 chaos 實驗自動化停止的決策依據(jù)。

在故障注入方面,設(shè)計可擴展的故障中心,實現(xiàn)精準可控的故障。 在實踐活動方面,確立混沌工程規(guī)范,探索最佳實踐。 解耦故障實現(xiàn)與 chaos 實踐活動管理。

所有故障的發(fā)生,都會間接或直接影響某個微服務(wù)。而我們的最終目的,是觀察該服務(wù)在各外部依賴異常時,服務(wù)本身的 resilience 能力如何。

Target - 即上文提及的目標微服務(wù),在開始 chaos 實驗之前,需要明確,對什么服務(wù)注入故障,該服務(wù)為主要觀察目標。 Scope Filter - 對應(yīng)混沌工程概念中的爆炸半徑,為了降低實驗風(fēng)險,我們不會令服務(wù)全流量受影響。通常會過濾出某一部署單元,該單元或為某一機房,或為某一集群,甚至精確到實例級別乃至流量級別。 Dependency - 依賴,我們認為所謂服務(wù)被故障影響,實際是其依賴有異常。該異??赡軄碜灾虚g件,可能來自某下游服務(wù),也可能來自所依賴的 cpu,磁盤,網(wǎng)絡(luò)等。 Action - 故障事件,即描述該服務(wù)的外部依賴究竟發(fā)生了何種故障,比如下游服務(wù)返回了拒絕,發(fā)生了丟包,或者延時;又比如磁盤發(fā)生了寫異常,讀繁忙,寫滿等意外情況。?
spec. //微服務(wù)application A 的 cluster1集群內(nèi)10%的實例cpu突然滿載
tareget("application A").
cluster_scope_filter("cluster1").
percent_scope_filter("10%").
dependency("cpu").
action("cpu_burn").
end_at("2020-04-19 13:36:23")
spec. //服務(wù)application B 的 cluster2集群所依賴的下游application C突然延時增加100ms
tareget("application B").
cluster_scope_filter("cluster2").
dependency("application C").
action("delay, 200ms").
end_at("2020-04-19 13:36:23")3.2.3 故障中心設(shè)計
我們在以上故障模型基礎(chǔ)上設(shè)計了一套聲明式接口。當注入某一故障時,只需按上述模型添加故障聲明即生效;若想終止故障,只需刪除該聲明。
故障中心在收到上述類似聲明后,便開始向內(nèi)部研發(fā)體系平臺尋找符合條件的實例,并自動安裝故障 agent,通過將相關(guān)指令下發(fā)給 agent,實現(xiàn)故障注入的目的。故障中心適當借鑒了 Kubernetes 的架構(gòu)設(shè)計與理念,其架構(gòu)設(shè)計如下:

故障中心架構(gòu)圖
故障中心由三個核心組件 API Server, Scheduler, Controller,外加一個核心存儲 etcd 組成。其中?
API Server負責(zé)包裝 etcd 并對外提供聲明式接口;
Scheduler 則負責(zé)將故障聲明解析,并根據(jù)聲明持續(xù)尋找 Target 對應(yīng)的實例,以及 Dependency 對應(yīng)的下游實例/中間件/物理設(shè)備;
在這之后,Controller 將 action 故障解析為可執(zhí)行指令,下發(fā)至對應(yīng)實例的 agent,或者調(diào)用對應(yīng)中間件的 API,達到精準的故障注入。
3.2.4 實驗選擇的原則
在 chaos 實驗中,我們考慮到風(fēng)險以及各業(yè)務(wù)不同特點對 chaos 理念的接受程度不同,所以定義了實驗選擇的原則,可供各業(yè)務(wù)線根據(jù)實際情況自行決定,其原則如下:
從線下到生產(chǎn)
從小到大
從面向過去到面向未來
從工作日到休息日
1)從線下到生產(chǎn)
此條指的是環(huán)境的選擇。
一般認為,混沌工程只有在生產(chǎn)環(huán)境實驗才有意義;但我們認為一種比較溫和的實驗步驟是從線下逐漸走到生產(chǎn)。這也是綜合考慮,從線下開始著手會讓各方都比較放心。不過對于分布式系統(tǒng)而言,部署不同、流量不同都會帶來不一樣的結(jié)果,唯有在生產(chǎn)進行實驗才能真正驗證。一條比較好的路徑是:
測試環(huán)境-> 預(yù)發(fā)布環(huán)境 -> 預(yù)覽環(huán)境特定流量 -> 生產(chǎn)集群生產(chǎn)流量
2)從小到大
此條指的是故障范圍的選擇。
我們推薦故障應(yīng)該從小范圍,較溫和的開始。當建立了足夠的信心之后,再進一步擴大故障范圍。一條比較好的路徑是:
可控流量 -> 單個接口 -> 單機 -> 單集群 -> 單機房 -> 全鏈路
3)從面向過去到面向未來
此條指的是故障類型的選擇。
我們認為曾發(fā)生過的故障是實驗優(yōu)先級最高的。而人類歷史告訴我們,人們總是會在一個地方反復(fù)跌倒;生產(chǎn)發(fā)生過的故障,很有可能再次發(fā)生;且同樣可能會在其他鏈路上發(fā)生類似故障。因此一條較好的路徑是:
重現(xiàn)歷史事故的故障 -> 來自歷史事故的故障類型 & 相似鏈路 -> 各種隨機故障 & 全鏈路。
4)從工作日到休息日
此條指的是混沌工程實驗時間的選擇。
休息日代指任意時間。我們推薦實驗時間從工作日開始嘗試,最優(yōu)的是工作日下午 3 點左右(各業(yè)務(wù)根據(jù)自身高低峰期再行考慮)。這個時間段,相關(guān)人員一般都在工作崗位上,有任何情況都能及時處理?;煦绻こ痰脑缙谀繕司褪菫榱嗽诳煽氐沫h(huán)境中提前暴露問題。當然,隨著混沌工程不斷走向成熟,我們將會慢慢開始嘗試在任意時間進行實驗。一條比較好的路徑是:
工作日下午 -> 工作日晚上 -> 休息日 -> 隨機時間
3.2.5 實驗過程設(shè)計
在該階段,我們?yōu)闃I(yè)務(wù)系統(tǒng)設(shè)計了 chaos 實驗過程的最佳實踐。按此過程,chaos 實驗將會更有目的,觀察到的內(nèi)容亦更有意義。
實驗前
0)?? 在開始你的第一個混沌實驗之前,請確保你的服務(wù)已經(jīng)應(yīng)用了彈性模式,并準備好處理可能出現(xiàn)的錯誤,否則不要隨意嘗試。
1)準備故障注入的能力
字節(jié)跳動混沌工程實驗平臺的故障模擬能力
聯(lián)系各依賴方手動制造故障
2)選定本次實驗的假設(shè),如:
不會因為某個下游服務(wù)掛了而影響業(yè)務(wù)。
不會因為 redis 網(wǎng)絡(luò)抖動而影響業(yè)務(wù)。
不會因為某個 pod 突然被殺而影響業(yè)務(wù)。
當某個核心下游依賴掛了之后,降級方案必須有效,且副作用可接受。
3)選定能體現(xiàn)實驗假設(shè)的指標,并觀察。
4)選定能反應(yīng)服務(wù)損失的指標,并設(shè)定底線。
5)在組織內(nèi)溝通到位。
實驗中
1)執(zhí)行期間要密切關(guān)注相關(guān)指標,因為可能需要隨時終止實驗。
2)牢記實驗的假定,收集相關(guān)指標稍后可輔助分析實驗結(jié)果。
3)在實驗過程中,可能會根據(jù)指標的波動情況,隨時調(diào)整實驗參數(shù)(故障范圍與烈度),多嘗試幾次,會有更好的效果。
實驗后
根據(jù)指標和業(yè)務(wù)表現(xiàn),分析本次實驗所能帶來的成果。根據(jù)經(jīng)驗反饋,一般會獲得以下相關(guān)成果:
找到了脆弱點,并獲得改進
驗證了降級/預(yù)案,增強信心
找到了系統(tǒng)性能拐點
梳理出一波無效告警,優(yōu)化告警效率
3.2.6?總結(jié)
在這一階段,我們對故障中心完全重構(gòu),在架構(gòu)上使得故障注入更加簡單可控;在模型抽象上,故障注入的擴展性更強。在這一階段,我們梳理了 chaos 實驗選擇與流程的最佳實踐。在下一代產(chǎn)品中除了繼續(xù)豐富故障能力外,將會著眼于補齊指標分析能力,以及進一步沉淀有更大產(chǎn)出的實踐活動。
3.3 第三代
在完成了初步階段的實踐之后,chaos 的核心能力-故障注入已經(jīng)具備,同時字節(jié)跳動各業(yè)務(wù)線也陸續(xù)開始了 chaos 之旅。于是該階段,我們的目標是:
在自動化指標分析方面,補齊指標分析能力。
在故障注入方面,豐富故障的類型。
在實踐活動方面,沉淀上一階段總結(jié)的實踐活動,并進一步探索實踐形式,挖掘更大的價值產(chǎn)出。
3.3.1 系統(tǒng)設(shè)計
基于以上目的,整體設(shè)計如下:

成熟階段系統(tǒng)設(shè)計
在原子能力層,添加自動化指標觀察能力。通過引入機器學(xué)習(xí),我們做到了基于指標歷史規(guī)律的無閾值異常檢測。在平臺層,添加自動化強弱依賴梳理,與紅藍對抗模塊。?
3.3.2 自動化指標觀察
在 chaos 實驗中,相關(guān)指標的梳理與收集是一件繁瑣且耗費心力的活動。我們觀察了 chaos 實驗過程之后,總結(jié)了三類指標,如下:
故障指標 - 確定故障是否注入成功 。
止損指標 - 確保系統(tǒng)不會因故障無法承受而造成過大損失。
觀察指標 - 觀察細節(jié),觀察故障導(dǎo)致了哪些關(guān)聯(lián)異常。
1)故障指標
指標定義 - 故障指標源于故障,因故障觸發(fā)了指標波動。比如我們注入了故障:redis 延時增加 30ms,那么該指標則為目標服務(wù) -> redis 之間的均值延時 pct99 延時等。該指標可幫助用戶直觀看到故障的產(chǎn)生與結(jié)束。
如何處理 - 對于此類指標,僅做展示即可,可以保證用戶清晰看到故障何時開始,何時結(jié)束。
獲得途徑 - 來自故障,平臺制造故障時,平臺知道會受影響的直接指標是什么。
2)止損指標
指標定義 - 止損指標對于目標服務(wù)/目標業(yè)務(wù)至關(guān)重要,表示該次演練所能承受的最大限度,指標可能來自服務(wù)本身相關(guān)(比如對外錯誤率),亦可能來自關(guān)聯(lián)較遠的業(yè)務(wù)指標(比如每分鐘點播量),甚至可能來自兜底服務(wù)的指標(比如兜底服務(wù)的最大承受指標);也可能是以上提到的各類指標某種組合。
如何處理 - 對于此類指標,需要非常精準地標識關(guān)鍵閾值,一旦波動到閾值時,表示到達了損失底線,任何操作必須馬上停止,故障需要恢復(fù)。
3)觀察指標
指標定義 - 觀察指標,對于在 chaos 實驗的時候發(fā)現(xiàn)新的問題,有很大的輔助作用。觀察指標應(yīng)該是一切與服務(wù)和故障相關(guān)的指標。比如服務(wù)本身的 SRE 四項黃金指標(latency, traffic, errors, and saturation),比如故障可能影響的關(guān)聯(lián)指標(redis 延時故障,是否會導(dǎo)致 redis 其他指標的變化?redis qps,reids errors,降級服務(wù)的 qps 變化),比如關(guān)聯(lián)告警記錄,關(guān)聯(lián)日志。
如何處理 - 此類指標,沒有明確的閾值,但往往此類指標在事后分析的時候最容易發(fā)現(xiàn)各種潛在問題,我們在處理此類指標的時候引入了機器學(xué)習(xí)方法,與指標歷史規(guī)律進行對比,可做到自動化異常檢測。
因此指標觀察的核心是智能指標篩選和無閾值異常檢測。另外配合一套基于經(jīng)驗的人工規(guī)則,我們可以面向不同的實踐活動做各類自動化判斷或者輔助決策。
3.3.3 紅藍對抗實踐
字節(jié)跳動的紅藍對抗實踐,吸收自 Gremlin 介紹的 chaos gameday[2]。在字節(jié)跳動內(nèi)部多次實踐中,我們也不斷因地制宜調(diào)整,最終發(fā)展成為字節(jié)跳動特色的紅藍對抗實踐。紅藍對抗的實施目標是幫助業(yè)務(wù)系統(tǒng)進行全面摸底,也可認為是對業(yè)務(wù)系統(tǒng)的穩(wěn)定性建設(shè)目標的一次集中驗證。
目前紅藍對抗已多次幫助字節(jié)跳動推薦中臺進行全面摸底,發(fā)現(xiàn)了從監(jiān)控、告警到兜底、降級、熔斷策略等各方面的問題。
1)流程設(shè)計
在開啟紅藍對抗之前,紅藍雙方的溝通特別關(guān)鍵。紅軍(即防守方)需要進行諸多決策,比如評估有信心參與對抗的服務(wù)與范圍,比如評估近期業(yè)務(wù)迭代節(jié)奏,權(quán)衡業(yè)務(wù)迭代與穩(wěn)定性建設(shè)。我們遵循如下流程進行實踐對抗前的活動正在完成平臺化沉淀:

紅藍對抗執(zhí)行前流程圖
紅藍對抗一旦開啟后,主要操作將由藍方主導(dǎo),除非發(fā)生預(yù)期外情況(這一般也意味著防守失?。┗蛘咝枰僮黝A(yù)案開關(guān),否則紅方在此過程中,基本處于 stand by 狀態(tài)。主要流程如下:

紅藍對抗執(zhí)行中流程圖
在對抗結(jié)束后的復(fù)盤回顧是關(guān)鍵環(huán)節(jié),通過將紅藍對抗過程中所記錄的數(shù)據(jù)匯總??汕逦乜吹綄拐w效果,一目了然地了解此次計劃中目標業(yè)務(wù)系統(tǒng)的穩(wěn)定性建設(shè)情況。

單場紅藍對抗數(shù)據(jù)匯總
另外,我們將過程中發(fā)現(xiàn)的問題匯總記錄,并保留對抗時候的完整記錄。這使得發(fā)現(xiàn)問題可追蹤,剖析問題有現(xiàn)場。

單場紅藍對抗結(jié)果匯總
3.3.4 強弱依賴自動化梳理實踐
服務(wù)的強弱依賴信息對于服務(wù)治理、容災(zāi)體系的設(shè)計都至關(guān)重要,而強弱依賴的真實情況只能在故障發(fā)生時才能得到驗證。故我們開啟了強弱依賴的驗證工作,并隨著實踐打磨,不斷提高強弱依賴梳理的自動化程度。在通過引入機器學(xué)習(xí)幫助我們進行無閾值指標異常檢測之后,強弱依賴梳理過程已基本實現(xiàn)全自動化。目前強弱依賴梳理已基本覆蓋抖音與火山的核心場景,為其服務(wù)治理與容災(zāi)體系設(shè)計都提供了巨大的輸入。強弱依賴自動化梳理的整體流程如下:

強弱依賴自動化梳理流程
3.3.5 總結(jié)
在該階段,我們補齊了指標分析能力,通過引入機器學(xué)習(xí),很大程度降低了指標分析成本。
基于自動化指標分析能力,我們嘗試結(jié)合新的實踐活動挖掘了更多的產(chǎn)出。紅藍對抗活動幫助業(yè)務(wù)系統(tǒng)對自身穩(wěn)定性有個更全面的了解。而強弱依賴分析則幫助業(yè)務(wù)系統(tǒng)對自身的穩(wěn)定性細節(jié)有了更深的認識。
四、未來階段:面向基礎(chǔ)設(shè)施的混沌工程
五、結(jié)尾
《混沌工程:Netflix 系統(tǒng)穩(wěn)定性之道》:https://www.oreilly.com/library/view/chaos-engineering/9781491988459/
《How To Run a GameDay》:https://www.gremlin.com/community/tutorials/how-to-run-a-gameday/
Netflix 混沌工程開源項目 - Chaos Monkey:https://github.com/Netflix/chaosmonkey
阿里巴巴 混沌工程開源項目 - ChaosBlade:https://github.com/chaosblade-io/chaosblade
PingCAP 混沌工程開源項目 - Chaos Mesh:https://github.com/pingcap/chaos-mesh
分布式一致性測試框架 - Jepsen:https://jepsen.io/
Zhou, Xiang, et al. "Latent error prediction and fault localization for microservice applications by learning from system trace logs." Proceedings of the 2019 27th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering. 2019. :https://dl.acm.org/doi/10.1145/3338906.3338961


