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