迄今見過最易懂的混沌工程落地實踐,針不戳!
一、背景
從 2010 年 Netflix 上線 Chaos Mokey 的第一個版本到現在,雖然混沌工程發展已歷時十年,但其實只在少數大廠里面有較成熟的落地,對絕大部分研發同學來說,混沌工程還是一個比較陌生的領域。
分布式和微服務化已經成為主流的系統架構設計方案,大規模分布式系統的可用性保障能力越來越成為關注的重點。混沌工程也開始如雨后春筍般在各大企業內部萌芽生長,但大部分還處于初期的探索階段,在實踐過程中也遇到了這樣或那樣的問題,有技術上也有認知層面上的,這些問題難免會對混沌工程的快速落地產生阻力。
下面介紹一下字節跳動在混沌工程實踐過程中的一個關鍵階段:場景化主動實驗。希望本文可以幫助大家加深對混沌工程價值的了解,對設計混沌工程實驗、落地混沌工程建設提供更多的思路。
二、什么是場景化主動實驗
混沌工程的高級原則要求能夠在生產環境自動的運行實驗,這個目標并不是一蹴而就的。
根據混沌工程成熟度模型(CMM)[4]說明,要分別從“熟練度”和“應用度”兩個維度同時進行建設。其中,“熟練度”體現了混沌工程系統的有效性和安全性,“應用度”衡量了混沌工程實驗覆蓋的廣度和深度。在混沌工程建設的中前期,這兩點都是混沌工程成功落地的關鍵路徑。
在混沌工程的初級階段,通常都會建設一個故障注入測試平臺(FIT,Fault Inject Testing),集成一些常見的故障場景或異常事件的模擬能力,由業務或 QA 同學設計并執行實驗來驗證系統的韌性能力。
在這個階段,基礎架構和業務系統的實現都可能處于比較粗放狀態,混沌工程平臺的故障注入能力需要兼容各種業務架構的實現方案和軟硬件環境,執行實驗時,業務同學不僅要設計實驗的故障場景(機房網絡故障、下游服務宕機等)、配置演練環境(目標服務、實驗集群等控制實驗的爆炸半徑),還要找到能夠描述實驗時服務狀態的穩定性的指標(如 metrics、日志或告警等),然后手動啟動實驗,執行人還要不停的觀察穩定性指標的變化,判斷系統的容災邏輯或彈性策略是否被正確觸發、業務系統的表現是否符合預期等等。如果在執行過程中發現異常,需要立刻終止實驗,收斂實驗影響。
整個實驗過程的人力成本較高,實驗的操作門檻也較高,再加上這個階段業務同學對混沌工程價值和理念的認知還處于較初級水平,很難會主動對自己的服務設計實驗,更無法保證實驗的常態化執行。因此,混沌工程實驗的時效性和業務系統的彈性容災策略持續有效就比較難以保證了。
如何突破這個階段、成功抵達混沌工程的終極目標呢?
通過不斷的思考,我們認為混沌工程建設需要一個過渡階段,即場景化主動演練。
所謂場景化主動演練,就是在明確混沌工程的終極建設目標的前提下,以終為始,分階段去設計混沌工程的實驗標準、定義技術規范,搭配工程化能力,逐步將人和業務引導到混沌工程建設的高速公路上,共同推進 CMM 模型的熟練度和應用度。
所以,場景化主動實驗是通向混沌工程自動化建設的關鍵路徑。
三、如何建設場景化主動實驗
首先需要明確混沌工程的最終目標,以終為始,反推當前階段應該建設什么樣的技術規范和標準能力。
然后,根據業務當前的基礎架構現狀和實驗訴求構建一個通用的實驗場景,由混沌工程平臺方在保證實驗風險可控的條件下主動對業務系統進行實驗。這樣,在滿足業務需要的同時又可以推動相關技術規范和基礎能力的建設,而且對業務同學的資源依賴較少。
以字節跳動為例,要實現在生產環境自動的執行可控的混沌工程實驗,當前階段應該具備的能力包括:
- 能夠在生產環境持續的運行實驗并具備實驗爆炸半徑的控制能力
- 選定一個命中業務痛點且通用的實驗場景,構建通用的自動化執行實驗能力
- 能夠描述服務穩定性的通用指標
- 自動檢測穩定性指標的變化
- 自動終止實驗【在實驗爆炸半徑可控的情況下,非必須】
四、主動實驗
FIT 平臺需要業務同學分析業務容災場景并制定實驗,然后執行實驗進行驗證,混沌工程平臺方只是給予一些技術支持和建議。在業務同學對混沌工程認知度不高情況下,實驗的主動性、覆蓋率、時效性都很難保證,如果再想讓業務同學去配合建設一些混沌工程的基礎能力難度就可想而知。
轉換一下思路,將業務主動改為平臺主動!由混沌平臺針對業務系統的某個場景主動執行混動實驗來驗證服務的彈性能力,業務同學只需關注實驗結果。只要實驗場景契合業務痛點、實驗結果對業務構建彈性系統有意義,業務同學自然會認可混沌工程的價值,也會更加積極的參與混沌工程實驗和混沌工程的基礎建設。
五、實驗場景
混沌工程的價值是發現業務系統中潛在薄弱環節,提升業務系統韌性能力,即服務可用性和穩定性,所以主動實驗場景也應該滿足這個前提。
在字節跳動,主動實驗落地的第一個場景是驗證服務調用鏈的強弱依賴關系。所謂強弱依賴關系,就是當訪問的下游服務異常(服務宕機、響應超時、接口返回失敗等)時,調用方的穩定性和可用性是否會受到影響。例如,查詢緩存 miss 或失敗后可以繼續回源訪問數據庫,緩存的問題并不會影響服務可用性,這個緩存就是個弱依賴。
為什么要選擇這個場景呢?公司的很多線上運營事故都是因為不合理的依賴關系導致的。字節跳動有很多高 QPS 的海量服務系統,為了保證用戶體驗,對高可用高穩定性的要求很高,會通過各種緩存、服務兜底、數據兜底等容災策略來減少強依賴服務的數量。另外,在字節跳動的服務治理體系中,會根據服務間的強弱依賴調用關系為某些故障場景預設自動容災降級的策略。比如,當服務治理系統檢測到系統負載過高時,能夠自動對弱依賴的下游執行降級,通過 FailFast 來緩解系統的負載。因此,業務負責人通常都會比較關注服務的強弱依賴關系。
六、自動化
主動設計和執行實驗意味著將業務側的人力成本轉嫁給了混沌平臺,混沌平臺必須要借助通用化、自動化的執行能力來降低人力成本。需要強調的是,這里的通用化和自動化一定是和混沌工程的終極目標一致的,能夠承載過渡階段的職責。
可以從混沌工程的高級原則[2]進行剖析:
- 服務的穩定狀態假設:找出能夠描述服務穩定狀態的通用指標,可以是 metrics、告警等。執行實驗前,這些穩定狀態指標應處于穩定狀態;執行實驗時,如果服務的可用性或穩定性受到影響時,穩定性指標會發生變化,比如 metrics 曲線的劇烈波動、觸發告警等;當實驗結束后,穩定性指標又會恢復到之前的穩定狀態。如果執行實驗時,穩定狀態假設發生了變化,說明這是個強依賴。
- 生產環境運行實驗:在風險可控的條件下推薦在生產環境運行實驗,因為系統的行為會根據環境和流量模式的不同而有所不同,系統用戶也不會像你所預期的那樣與你的系統進行交互。當然,在生產環境執行混沌工程實驗很可能是有損的,為了避免對用戶體驗產生較大影響,一定要控制好實驗的爆炸半徑,比如篩選出少量的實驗流量,這就要求混沌平臺具備實驗流量篩選與調度的能力。
- 多樣化現實世界事件:也就是各種故障的模擬能力。因為是場景化實驗,所以對多樣化的訴求倒不像 FIT 那樣強烈。
- 最小化“爆炸半徑”:如果選擇在線上環境執行實驗,需要具備篩選實驗流量的能力,即篩選出滿足實驗所需的最小流量即可,嚴格控制“爆炸”的影響范圍。
- 持續自動化運行實驗:通過工程化能力將實驗目標過濾、實驗流量篩選、執行實驗、穩定狀態檢測、生成實驗報表、實驗結果反饋收集等流程串聯成自動化的執行流,減少人力依賴。另外,混沌工程實驗從來都不是一錘子買賣,應該通過常態化的運行實驗來持續的保證服務的高可用和彈性機制符合預期。
七、服務標準與技術規范
一個公司內部通常會有很多條產品線,每個產品又會包含很多微服務,還會依賴到中臺服務或基礎組件,這些不同模塊的開發語言、服務框架、技術棧等可能五花八門。要想實現混沌工程通用化與自動化的能力,就必須制定一些通用的服務標準和技術規范。
混沌工程不僅需要了解業務系統當前的技術棧,還要能夠預測未來的技術發展趨勢,幫助業務提前規劃切實可行的技術規范并協助進行建設。
舉個例子,如何定義服務的穩定狀態?
在字節跳動,我們以調用方視角定義了一個服務級別的 metrics 指標來描述服務的穩定性狀態:
- 被調方在響應包中添加一個通用的 stability 字段來標識本次請求的處理結果是否成功
- 調用方從響應包中解析出 stability 字段并上報 metrics。某些異常場景(如被調方無響應)導致調用方無法解析出 stability 字段,會上報一個特殊的不穩定值。
之所以要在響應包中單獨定義一個 stability 字段是為了區分開系統錯誤和業務錯誤。因為業務錯誤并不表示服務出現了問題,所以我們更關注系統錯誤。舉個例子,刪除好友時被調方返回好友不存在的錯誤,這個錯誤并不表示系統的穩定性出現了問題。
這個規范最開始只在字節跳動的少數核心服務中使用,其他服務通常都有自己的穩定性指標,有些服務可能需要多個 metrics 指標一起來描述服務的穩定性。因為混沌工程的通用性要求應該具備一種通用的指標來描述所有服務的穩定性狀態,經過評估,我們將 stability metrics 作為了混沌工程的服務通用穩定性描述指標,并計劃將其推廣到全公司的業務,無論什么服務框架和開發語言都可以低成本的快速實現。
八、字節跳動的混沌工程概況
字節跳動的混沌工程體系主要包括場景化主動實驗平臺、FIT 平臺和紅藍對抗平臺。
- 場景化主動實驗平臺:以平臺視角主動對業務發起混沌實驗,在驗證業務系統的高可用和彈性能力的同時推動服務標準化和技術標準化建設,提升混沌工程價值產出和影響力,為實現混沌工程的終極目標做好鋪墊。
- FIT 平臺:業務同學自助驗證服務容災機制的正確性,具備各種異常事件和故障模擬能力,提供了靈活的可視化實驗編排能力。
- 紅藍對抗平臺:以第三方視角,用系統化、隨機化的對抗實驗方式來驗證業務系統的高可用水平、監控和告警的有效性,以及異常情況下人工介入時機、故障定位和故障恢復時間是否達標等。
九、字節跳動的場景化主動實驗建設方案
1. 實驗目標
同時推進混沌工程建設的“熟練度”和“應用度”,以生產環境自動執行混沌工程實驗為目標構建場景化主動實驗的流程和標準,實驗場景選定為驗證服務間的強弱依賴調用關系,可自動化運行實驗,具備實驗爆炸半徑控制能力。
通過驗證強弱依賴調用關系的正確性反推服務的穩定性指標是否規范,推動穩定性指標的規范落地。
2. 實驗對象
優先在字節跳動的核心服務落地,樹立模范標桿,然后擴展到更大范圍。
3. 穩定性指標&波動自動化檢測
穩定指標:
因為 stability metrics 已經被多數核心服務當做通用的穩定性描述指標,所以場景化主動演練將 stability metrics 作為穩定性描述的核心指標,同時輔助判斷接口成功 qps、失敗 qps、調用下游成功 qps、失敗 qps、pct99 等指標。
指標波動檢測方案:
自動化執行實驗要求混沌平臺能夠自動檢測穩定性指標的變動,因為不同服務的指標曲線是不一樣的,同一服務的不同時刻的指標曲線也是不一樣的,所以預置曲線波動的閾值上限的效果肯定不會太好。因此,在項目啟動階段我們就直接探索自動化的動態檢測 metrics 曲線波動的方案:
- 一種是 Netflix 介紹的 AB test 方案,對比實驗曲線和樣本曲線的差異
- 一種是實時計算曲線的變化趨勢
由于方案一要求具備更靈活的流量篩選能力和實驗環境隔離能力,當前階段的建設難度和成本較高,所以我們選擇了方案二。
自動化波動檢測:
- 起初我們參考線上報警的檢測方案:在執行主動演練時,先通過機器學習為穩定性指標實時訓練檢測模型,然后用模型實時檢測指標曲線的變化。但是,因為主動實驗的時間較短(一個實驗節點只有 60~120 秒)、metrics 數據點稀疏(一個節點的實驗時間只能采集到 2~4 個數據點)、實驗流量較低(爆炸半徑控制在 5~10 QPS),所以基于機器學習的檢測效果并不理想。
于是,我們改成組合多種統計規則的檢測算法,根據最近一段時間的歷史數據動態生成曲線的合理波動范圍閾值,然后在實驗過程中實時檢測增量數據點的波動范圍。如果數據點超出了波動范圍閾值,就被判定為不穩定。
經過不斷調優,最終把這個場景下的指標檢測效果優化到了預期水平。
優化方案:
- 在實踐中,我們發現單個穩定性指標的曲線會偶現非預期的波動噪音,這些噪音會影響曲線檢測結果的準確率。
于是,我們增加了一個噪音過濾策略:通過對比有相關性的多條穩定性指標曲線的波動相似度來過濾噪音。舉個例子,對下游依賴服務注入故障后,調用下游服務失敗的 metrics 曲線會上升,如果穩定性指標曲線也上升,而且這兩個曲線的變化趨勢也相似時,才會認為曲線變化是受實驗的影響。這個策略能夠比較有效的過濾掉偶現的曲線波動噪音。
具備了穩定狀態的檢測能力,在場景化主動實驗時就可以根據穩定狀態的檢測結果自動推斷下游依賴服務是強依賴還是弱依賴。
4. 最小化爆炸半徑控制
為了保證實驗的通用性和降低構造實驗流量的成本,我們選定在生產環境執行實驗,因此最小化爆炸半徑控制能力就非常重要了。
字節跳動的生產環境有個用于服務灰度上線的金絲雀集群,在服務上線時會先升級這個集群來驗證服務的正確性。這個集群的實例比較少,且支持通過修改集群權重來調整進入集群流量。
經過驗證,實驗流量在 5~10QPS 時就可以保證穩定性 metrics 指標檢測的準確率。所以,執行實驗時,先從服務的金絲雀集群中隨機選擇一個實例作為實驗目標,計算實例流量與預期流量的偏差重新生成權重值,然后通過修改集群權重來調整實例流量。
5. 驗證方式
字節跳動的微服務管理平臺通過聚合服務的 Trace 日志生成了服務間的調用拓撲圖,通過 OpenAPI 可以查詢到某個服務的所有一級下游依賴服務列表。
然后,逐個對下游依賴服務注入一段時間的宕機故障,同時檢測服務的穩定性指標是否出現異常波動來推斷下游依賴服務是強依賴還是弱依賴。
需要注意的是,因為是逐個對下游依賴服務執行實驗,為了避免前一個實驗對下一個實驗產生干擾,我們在兩次實驗間增加了一個間隔時間,具體的間隔時長依賴所使用的指標檢測算法。
6. 實驗報告
實驗執行結束,平臺會將下游依賴服務的強弱依賴推斷結果、執行上下文、穩態指標監控視圖和檢測結果等匯總成一個實驗報告發送給服務負責人。
服務負責人確認實驗報告,如果發現實驗結果不符合預期,可以通過執行上下文和監控視圖等信息來輔助定位問題。同時,可以在實驗報告中備注不符合預期原因、問題修復方案和修復進度等,平臺會定時跟進修復進度并提醒服務負責人更新結果。
如果實驗結果符合預期或問題已完成修復,實驗報告會進入結單狀態,同時記錄服務的強弱依賴推斷結果,并輸出給服務治理平臺,應用于服務在線治理。
7. 實驗結果自動保準
業務系統是持續迭代的,下游依賴關系也是動態變化的。如果非預期的引入了強依賴,會給系統增加可用性風險,因此場景化主動實驗也需要常態化執行。
已完成的主動實驗都可以開啟試驗結果自動保準,每隔一定時間會自動執行實驗驗證下游依賴服務的強弱依賴關系,并與歷史實驗結果進行對比,并將變動的部分通過實驗報告發送給服務負責人。
經過服務負責人確認后,新的驗證結果會被更新到存儲和發送給服務治理平臺。
8. 完整的實驗流程
十、場景化主動實驗的價值
我們的驗證范圍從核心服務開始、逐漸向外圍服務擴張。
核心服務的驗證結果基本符合預期,但還是有少數個案存在穩定性指標不規范、容災邏輯不符合預期的情況。通過實驗結果自動保準機制,也多次及時發現因代碼變更所導致的容災邏輯失效情況。
外圍服務驗證出來的問題就比較多了,穩定性指標嚴重不規范導致無法評估服務的穩定性、容災邏輯覆蓋率低導致過多的強依賴使得服務可用性風險較高等等。需要持續的推動業務進行優化升級,并給予一些高可用彈性系統的建設思路或參考方案。
十一、場景化主動實驗近期工作
最近,我們新上線了在結果保準時自動對弱依賴服務注入隨機故障來進一步探索弱依賴的抗風險能力。我們認為弱依賴服務在任何故障場景下都不應該影響服務的可用性。
另外,場景化主動實驗還接入了服務的上線流程,在服務灰度上線時就觸發實驗,讓服務負責人能夠更及時的發現不符合預期的系統變更,如果有必要可立刻終止或回滾上線變更。
十二、場景化主動實驗的未來規劃
通過場景化主動實驗,我們已具備持續保障字節跳動核心服務的穩定性、指標規范性、強弱依賴正確性,以及弱依賴的抗風險能力等等。
接下來,我們會把場景化主動實驗擴展到更大服務范圍和更多業務場景,讓場景化主動實驗發揮出更大的價值。
另外,我們也在思考打通服務上下游,從點到線再到面,以更高維度的系統視角來探索啟發式的智能混沌實驗。