穩定性全系列(三)——放火&降級演練

目錄

1、背景

2、混沌工程

3、放火&降級演練

3.1、變被動爲主動

3.2、前提條件

3.3、方案實施

1. 選擇一個放火事件

2. 確定燃燒半徑

3. 制定預案

4. 確定計劃

5. 開始放火

6. 記錄和分析結果

4、總結


1、背景

系統穩定性建設一直是研發、測試、運維團隊繞不開的話題,這麼多年來,我們爲降低系統複雜度、提升系統可維護性絞盡腦汁,微服務架構本質是從架構層面來分而治之、化繁爲簡來解決系統複雜度問題,就像我們現在遇到的,微服務架構可能解決了研發問題,但並不是沒有“副作用”,它增加性能、服務治理、運維等開銷,同樣,也給系統穩定性建設帶來不少挑戰。

隨着業務的迭代,系統複雜度也在逐步變化,哪怕是資深架構師,一時也無法說清楚整個系統架構,穩定性工作如履薄冰,之前我們在做的一些諸如監控告警建設、線上全鏈路壓測、彈性雲擴容演練等工作,都是被動的爲未來可能的風險做準備,我們沒有標尺來衡量我們穩定性工作做得好不好,能打多少分,長期以來,參與這些工作的同學容易“疲憊”。這些未來的風險猶如未定期的大考,讓我們“既期待又惶恐”。

2、混沌工程

於是我們在想,能不能提前“放火”——人爲製造故障?就好比人類在爲了抵禦病毒的攻擊,製造了疫苗,而疫苗的本質其實就是被虛弱的病毒,我們爲什麼不能在系統中注入一些弱化的故障,來看系統的反應,以方便我們更有針對性的去做措施?

Netflix把自己在雲上的實踐提煉出來,寫了《混沌工程(Chaos Enginnering)》一書,相信裏面的一些體系化的思路對大夥會很有啓發。所謂混沌工程,其實一種應用經驗探索來學習系統行爲的方法,按照Netflix的說法,混沌工程是一門學科。那麼它與“故障測試”有什麼區別嗎?書中也做了簡單解釋,混沌工程和故障測試在關注點有一定的重合度,後者只是測試的一種方法,而前者是爲了生成“新信息”的一種實踐,這裏的“新信息”我理解是關於系統在某些事件發生後所產生的行爲的相關信息(而不是像故障測試一樣只關心是否產生了對的結果),而這種信息很有可能是我們都難以預料的,混沌工程的本質目的是我們不斷去調整系統,使系統根據彈性,這樣一來一旦緊急事件發生,系統的行爲會變得更加可預測,這也意味着對業務和用戶的影響更加可控。

3、放火&降級演練

3.1、變被動爲主動

就像前面提到的,之前我們大多數穩定性工作都是被動的爲未來的發生的緊急事件做準備,我們認爲放火演練將改變這一局勢,我們能人爲提前注入故障,來看看我們系統的反應是否符合我們預期。如果系統的反應沒有達到預期,故障帶來的影響面也比我們預估的要大,那我們就應該好好分析到底問題出在哪裏,該如何去修復。就應該是這樣,只有我們清晰的看到系統的穩定性問題,才能更有動力去解決該問題。有了放火演練,我們能將更多的“假想敵”活生生構造出來。

關於放火演練,還有一點非常重要,那就是降級預案(更通俗的說就是緊急預案),降級預案按照生效方式,分爲自動預案手動預案兩種,當然,預案的建設得依靠工具,在自動實施的預案中,只要我們定好策略,降級工具(例如 https://github.com/didi/sds)會在系統達到某種預先設定的條件下自動處理,而在手動預案的實施過程中,我們可能需要進行業務開關、系統開關、服務降級、切流等操作,較成熟的預案會將這些操作收口,可能只需要點一次按鈕就能完成整個預案的實施。理想的情況應該是,線上80%的預案是自動預案。

所以我們得出如下大致步驟:

我們常常把放火和預案結合在一起來演練,一方面我們要檢測在緊急事件發生時,系統是否有超出我們預期的行爲,另一方面我們也需要不斷找機會來驗證我們預案的有效性。介於此,我們也希望放火&降級演練能成爲工程師瞭解自己系統行爲的一個橋樑,來驅動和幫助工程師構建更具“彈性”的系統。

3.2、前提條件

我們前面已經提到了“放火”和“混沌工程”的概念,在滴滴內部,已經有定期的“盲測”演練,其實也屬於放火的範疇,但“盲測”的主要目標是使因機房問題導致的故障能在X分鐘內發現和資損,例如我們會定期隨機停掉一臺交換機,看下網絡設施是否做了足夠的容錯。看似簡單明瞭的舉措,實際上前期已經做了充分的準備,需要記住的是,並不是任何系統都能做放火&降級演練,必須要具備如下條件才行:

能使用線上環境:如果最終不能在線上或類線上的環境進行放火,那麼放火發現的行爲和得出結論將沒有實際的價值,所以請務必能申請到在線上環境實施。

完善的監控與告警機制:如果我們連線上系統的基本指標和行爲都不清楚的話,何來預期的結果?這需要監控系統幫我們完成。另一方面,我們總不能一直盯着監控大盤來看指標,需要報警系統來保障我們能及時發現系統異常。

可預估的燃燒半徑:在放火體系中,我們把它對系統的影響面形象的稱之爲燃燒半徑,放火的首要前提一定是對業務和系統的影響控制在預期範圍之內(例如XXX放火後發單接口的avg耗時漲幅不超過20%、發單量波動小於2%),前期的放火當然難以較準確的評估爆炸半徑,所以我們要先“放小火”,後面再逐漸加大馬力。

有對應的降級預案:在具體實施時,我們要對放火的內容進行歸類和沉澱,每種放火我們要提前想好對應的降級預案是什麼以及預案的觸發條件。初步的降級預案是放火的前提條件,而放火最終也會促進降級預案的不斷完善和進化,這是一個良性循環。

3.3、方案實施

首先我們必須承認一個事實,哪怕是經驗再豐富的工程師,也無法窮舉未來可能發生的緊急事件,更不要說這些緊急事件的組合了。想要真正開始放火其實並不容易,目前我們是按照如下步驟展開:

1. 選擇一個放火事件

其實最先做的應該是放火事件的歸類,由於我們更關注服務端的系統穩定性,所以主要把放火事件類型分爲五類:

存儲放火:包括Redis、MongoDB、ES、MySQL等錯誤量和耗時的放火。

依賴服務放火:包括下游調用超時、拋異常等。

消息放火:主要是針對MQ的放火,包括減少Consumer、增加Producer發送耗時等。

服務器放火:主要包括CPU、內存等服務器資源放火。

網絡放火:主要包括網絡帶寬、網絡節點的放火,例如前面提到的盲測。

由於放火&降級演練是定期舉行的,所以每種類型的放火事件我們都有機會嘗試。例如,我們可以選擇依賴服務放火類型,即線上通過經緯度反查城市ID的服務耗時比平常翻一倍這一放火事件。

2. 確定燃燒半徑

燃燒半徑即放火範圍,燃燒半徑的選擇一定要十分小心,不能過小,否則效果不明顯,不能過大,否則將影響線上業務和用戶,當然還是建議從小到大,逐步調整,比如這次我們選擇燃燒半徑爲線上10%的經緯度反查城市ID的服務。

3. 制定預案

一旦放火開始,線上應該具備哪些預案?哪些預案將自動生效?哪些預案需要人工干預?這一塊要提前想清楚並整理好,特別是終止預案,即當發生什麼情況或接收到什麼告警時應該立即停止放火,預案梳理也是工程師站在更高視角來審視整個系統風險點的機會。

4. 確定計劃

確定好放火時參與的團隊和人員,以及及時知會其他支撐團隊,通知客服和業務方等。確定好時間,初期可以選擇業務低峯期放火,條件成熟以後,可以逐漸往業務高峯期遷。

5. 開始放火

你肯定會問怎麼去放火?放火當然要藉助工具,例如阿里開源的混沌工具ChaosBlade就不錯,我們也是利用它來實現放火,放火架構圖如下:

圖的右側是業務系統集羣,每個模塊的機器上都會安裝一個放火Agent,用來接收和實施放火指令,並收集必要的數據,放火Agent如何實施放火指令呢?答案就在ChaosBlade中,內部實際上是使用JVM agent的注入能力(參見:https://blog.csdn.net/manzhizhen/article/details/100178857);而左側的放火平臺提供了放火的操作功能界面以及一些簡單的數據大盤。由於我們使用了Dubbo,所以放火平臺需要從Dubbo註冊中心取服務拓撲,而爲了放火平臺能做得更通用,所以有個dubbo-fire模塊進行服務拓撲的適配和轉化等,還提供緩存功能。

可以看到,整體的放火架構還是很簡單的,目前滴滴的放火平臺還處在快速迭代中。

記住一點,一旦達到終止放火的條件(例如影響的用戶數或系統指標超過預先確定的閾值),一定要及時的停止放火。

6. 記錄和分析結果

我們需要記錄系統在放火過程中的表現、對業務的影響、預案的效果等,然後進行討論和分析,這是不是我們想要的?怎麼做才能讓該緊急事件對系統和業務指標的影響更小?

我們需要把所有的放火演練沉澱下來,這些和歷史的線上事故一樣,是值得反覆研究和學習的,特別是對於新同學。

4、總結

就如我們前面說的,放火&降級演練是穩定性建設中少有的“主動”抓手,它裏面蘊含了很多實踐理論,需要我們在演練過程中不斷學習和沉澱;放火&降級演練也是工程師和自己所建系統關於“非功能特性”的一次深入互動,這種經驗在後續日趨複雜的服務端系統建設中尤爲重要。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章