持續保障系統穩定性和高可用:騰訊游戲混沌工程實踐
最近一兩年,我們可以發現混沌工程這個技術變得十分火熱,大家都知道它變成了一個新的風口。常說做事情要順勢而為,我們希望能夠抓住這個機會,所以我最近一年的工作主要是將混沌工程這一技術在騰訊游戲落地。
一、什么是混沌工程
1、混沌工程的定義
混沌工程是為應對故障而生。大家知道我們運維人員都很辛苦,經常在周末或者半夜起來處理各種各樣的故障。為了減少這種現象,更加有效地應對故障,混沌工程應運而生。
混沌工程是通過主動注入故障的方式,提前將系統的問題暴露出來,發現系統可能存在一些風險點,然后把這些問題提前解決掉。即使我們系統半夜或者周末發生故障,我們也可以安穩地休息。
上圖中的內容是Netflix那本書中對混沌工程的定義,簡單說就是通過主動注入故障的方式、提前發現問題,然后解決問題、規避風險。
2、混沌工程的作用
混沌工程的出現是為了有效應對故障,其作用具體可分為以下六點。
1)故障預防
混沌工程的核心點是預防故障,通過主動注入故障的方式將故障提前解決掉。
2)故障發現
混沌工程能夠提前幫助我們檢測故障。例如,我們通過混沌工程來檢測我們的告警監控系統、輿情,定期巡檢這些系統是否有效。通過注入故障驗證系統的有效性,從而提高我們故障檢測的速度,縮短故障平均檢測時長。
3)故障響應
做混沌工程也可以加快我們的故障響應速度。例如,我們可能經常在下班之后做混沌工程,看我們團隊的響應速度如何,是否在組織協調方面存在一些問題。這樣能夠提高我們整個團隊的戰斗力和故障響應的速度。
4)故障定位
混沌工程還可以幫我們定位故障。通過混沌工程可以判斷故障是否能夠及時被檢測到;我們系統的一些巡檢工具、Matrics、Log、Trace等可觀測平臺,它們的有效性是否可靠;我們的診斷工具是否能夠能夠及時定位到根因。這樣可以加快我們故障定位的速度,提高效率。
5)故障恢復
發現故障后,我們要修復故障。我們通過混沌工程也可以檢驗故障切換、限流熔斷、降級等策略以及應急預案是否有效,能不能快速地修復故障,縮短我們故障的平均修復時長,這也是我們做混沌工程的一個重要出發點。
6)復盤改進
故障結束之后,我們經常要對故障進行復盤。故障修復后,我們在生產環節很難復現。通過混沌工程我們可以非常簡單高效地復盤我們項目已經發生過的一些故障,這也是混沌工程的一個重要作用。
綜上所述,混沌工程通過提前主動注入故障、發現問題、解決問題的方式,降低我們生產環境中故障發生的概率。
二、混沌工程平臺建設
具體到混沌工程的實踐,業界有一套方法論。通過理解與總結,我把它分為5個環節。
要搞混沌工程,首先要有一個平臺。這個平臺可以做出故障、實現故障的編排、同步觀測實驗效果以及輸出實驗報告。完成實驗之后發現、跟進、解決問題,將問題解決后再次提交驗證,通過這一閉環,不斷地提升業務的穩定性與可靠性,就是做混沌工程的核心理念。
在騰訊游戲的具體落地中,我們通過混沌實驗的全生命周期來設計這一平臺。
1、流程設計
1)實驗前
做一個實驗,首先要有創造、注入故障的能力,要有故障場景,這里的故障場景就是指故障原子。我們希望實驗平臺能夠提供豐富的故障原子,將這些原子組合起來模擬出現網可能會發生的各種故障。
在實驗過程中,實驗平臺要能夠打通我們當前系統或公司已經存在的一些監控系統,例如一些基礎監控,或者業務特性的指標監控,并將其對接集成到實驗平臺。
我們混沌實驗平臺還需要管理我們的實驗目標。例如我們的一個K8S集群、一批IP或者一個物理機群等,要能夠對靶點進行分類,對通常說的爆炸半徑進行管理。接下來,我們要能夠對實驗做編排,通過一些拖拉拽的方式,將一次混沌實驗編排進來,這是這個平臺在實驗前應具備的能力。
2)實驗中
實驗中,我們的核心點是希望平臺能夠注入故障,同時觀察實驗的效果,即一邊做實驗一邊看效果。
實驗的過程中可能會出現一些我們預料之外的異常情況,我們要有兜底的策略,能夠在極端情況下自動停止實驗。做到很好的實驗防護,也是我們這個平臺需要具備的能力之一。
我們還希望平臺具有故障恢復的能力。做完實驗后,現場環境就能夠及時恢復。
3)實驗后
實驗結束之后,平臺需要輸出實驗報告。實驗發現的問題需要通過實驗報告呈現出來。我們要對實驗報告進行匯總分析,看是否發現了新問題、新隱患或新知識。我們得到結果要去分析,發現問題要去跟進,落實到人將問題處理掉。
我們還要進行大量的統計分析。例如游戲的的質量評分如何,英雄聯盟手游最近上線,通過統計分析,它的得分非常高,穩定性和可靠性也非常好。
2、故障原子
混沌實驗平臺最核心的能力是故障注入,人為地制造各種各樣的故障與破壞。
騰訊游戲主要使用自研的混沌工程引擎,以及引用一些其它的業界開源引擎。我們引用了Chaos Mesh等引擎來對我們的實驗做集成。有了這些底層的引擎后,我們就獲得了許多故障原子。
- 存儲層面:Io高負載、Io延遲、Io錯誤、文件句柄耗盡等故障原子。
- 計算資源層面:CPU負載高、滿載等故障原子。
- 網絡層面:時延、丟包、亂序、重復,帶寬滿,端口耗盡等故障原子。
- 節點/容器層面:關機一分鐘、刪pod、殺容器、殺pod等故障原子。
- 應用層面:進程將死、進程崩潰、HTTP協議狀態碼錯誤等故障原子。
- 自定義:可以制定一個機器腳本,例如自己寫一個shell腳本、Python腳本,或者go二進制包。上傳這個包,我們可以對其注入故障,這樣就可能對一些特殊的業務場景做定制化的開發。
基本上有了這些故障,我們在生產環境中或實驗環境下,就可以通過隨意的組合,模擬出現網各種各樣的故障。
3、應用故障注入
推薦一下Chaos Mesh產品,它專門為K8S場景設計,可以模擬包括pod、網絡、Io、內核等多種各層面的故障。我們使用了Chaos Mesh產品一年多,使用效果不錯。有了這個工具,我們在K8S環境下就可以直接注入故障,成本較低。
我們在實驗過程中發現,即使有了計算資源、網絡等基礎層面的故障原子,也不能完全滿足需求。我們有時候要經常對服務做一些應用層面的故障原子。因為騰訊游戲的服務大部分走HTTPS協議,有時可能要去對服務的某一個路徑、某一批用戶或某一個大區的玩家等做故障實驗,這時就要通過網關MESH這一流程來做這個實驗。
我們服務架構上面的每一個服務前面都有一個網關,所有流量都會經過網關流到真正的后端服務。對網關下發指定或者遙測等是通過統一的平臺實現的。
所有流量都會經過網關,那么網關就可以對流量做治理。很多公司應該都會采用這種架構對流量做治理,我們可以做流量的限速、降級、熔斷等。除此之外,我們還可以對流量做一些劫持、二次處理,這也就是混沌工程可以做的事情。
具體來說,流量從網關進來后,我們可以修改它的狀態碼。例如本來的狀態碼是200,我們修改為4xx;或者可以注入一個延遲,把這個服務sleep一段時間之后再返回;再者我們還可以對Header做一些注入,對剝離做修改等,甚至對帶寬做限制、對用戶做過濾。這樣的話混沌工程就可以在應用層面對玩家做故障注入了。
用傳統的引擎做應用層面的故障注入成本很高,但是有了網關MESH能力,我們做故障注入的成本會非常低。
舉個例子,我們想對某一個或某一批玩家做故障注入,配置起來很簡單。我們只需要在平臺上選擇我們的實驗對象,配置好規則并提交,實驗就可以馬上生效了。
這時我們就可以在客戶端上,體驗故障注入是否有效果,以及對玩家有何影響。這樣做故障只影響到這一批玩家,對現網其他的玩家沒有任何影響,我們的爆炸半徑就可以得到很好的控制,故障范圍、故障風險也可以得到一定把控,這也是網關MESH能夠帶來的收益。
4、實驗編排
毫無疑問,故障注入是混沌工程的核心能力,但除了故障注入外,混沌實驗平臺還應該具備一邊做實驗一邊觀察效果的能力。
平臺需要能夠編排?,F網的實驗可能非常復雜,故障可能通過各種實驗場景的組合才會復現或模擬出來,還有我們的實驗目標、靶點、實驗對象,我們要有一個地方將實驗配置集成管控起來。
例如上圖中,我們想把CPU燒到80%并持續10分鐘,就可以通過這個表單提交。我們想延遲一秒并持續10分鐘,也可以通過這個表單提交。
這樣的話我們的實驗目標、實驗配置以及我們想要觀察的穩態指標(做實驗過程中想要同步觀察的指標),都可以通過編排的方式串聯起來。編排能力可以大大提高我們的實驗效率,這個能力也是混沌工程實驗平臺必備的能力。
5、實驗觀測
有了編排,我們還希望在真正做實驗時同步觀察實驗的效果。這個實驗效果可能是來自一些基礎監控平臺的指標,例如最基礎的一些IaaS層的監控;也可能是QPS、延遲、同時在線人數等相關的一些業務特性指標,這些指標混沌平臺是沒有的。
在騰訊游戲,我們將基礎監控以及業務的一些特性監控打通、對接、集成,這些已經有的指標可以直接集成進來,沒有的我們也提供了普通標識,用戶可以直接把指標暴露出來,在平臺配置采集規則,這樣我們可以主動把用戶的業務指標拉過來,從而實現在平臺做實驗時,同步觀察這個實驗對用戶服務的影響。這一方法實現了整個指標透明化,是實驗觀測所獲得的收益。
6、實驗報告
做混沌工程,實際上有些類似于去醫院做體檢。去醫院做體檢之后,醫院一般都會輸出一個記錄身體各種指標的報告。這些身體指標有沒有超過健康的閾值,報告中都會有標記。醫生發現參考值過高時,會提醒我們在相關方面多加注意,并提供一些建議,到下次體檢時具體關注這些指標有沒有改善。
做一次體檢,我們最想獲得的就是這個報告,這個報告能夠體現出我們做體檢的收益。做混沌工程也一樣,我們做了混沌工程實驗,到底有沒有收益,有沒有發現問題,要在報告中體現出來。
我們希望這個平臺能夠將整個實驗過程中的一些歷史數據、編排數據、穩態指標等數據永久持續化存儲下來,這樣的話,我們后續就可以隨時回溯我們這個實驗的過程數據。
有了數據之后,我們希望能夠分析這些數據,發現問題。發現問題才是做混沌工程的目標。發現問題后,我們希望能夠對問題進行分類,并把問題落實到具體的責任人,讓他來跟進解決。這樣的話,我們這個實驗才會實現很好的閉環,也就是上文中提到的核心理念。不斷地發現問題、解決問題,并且形成循環,這才是我們實驗的初衷。
7、收益
做了這么多,有了故障原子、實驗編排、實驗報告,有什么收益呢?
大家也知道,沒有提出混沌工程前,我們也會進行一些容災演練,好像沒有混沌平臺也能夠做這件事情。
經過實驗,我們總結的收益點如上圖所示。
沒有混沌平臺的時候,我們去做實驗,要自己寫腳本、寫工具、開發工具、測試、編排,一個復雜場景可能要自己去串聯。我們還要去執行、觀察效果,效果數據可能分散在各種平臺,我們可能要不斷地通過在各種平臺之間切換,才能看到實驗的效果數據。一個故障演練下來至少是小時級以上的。
有了混沌實驗平臺,我們做實驗的效率大大提升了。我們編排一個實驗,編排它的靶點、實驗配置、觀測指標,幾乎可以做到分鐘級。幾分鐘時間,我們就可以把整個實驗編排出來,然后一邊做實驗一邊觀察效果,同時去發現問題、分析問題,大大縮短了實驗時間。
總結來說,降本增效就是做混沌平臺收益點。
三、混沌工程實踐
有了平臺大家不一定使用,我們要進行實踐。
實踐的目標非常清晰,要提升我們基礎設施、平臺、業務與應用的可用性與穩定性,要檢驗組織的協同效率,檢驗組織的協作方式、流程是否合理。
我們有以下幾個實踐要點:
- 控制風險。
- 自動化實驗。我們現在很多業務的版本迭代速度非???,如果每發布一個版本,我們都要去跟進、做實驗,會產生極高的人工成本,所以我們需要去做一些自動化的實驗。
- 紅藍對抗。提升組織團隊的協作能力。
1、控制風險
做混沌工程會對業務和系統產生破壞性。我們做混沌工程目的是通過主動輸出故障,發現問題、解決問題,所以風險控制是非常必要的。
一些教材或者文章都推薦混沌工程要直接上生產,這個理論沒有錯,實驗全部在生產環境上做,產生的報告是非常有說服力的。但在生產環境做實驗,會帶來很高的風險,也會產生極高的人力成本。如果哪一方沒參與,他的服務出問題,可能就會導致現網的嚴重事故。實驗一旦超出我們預想的情況,可能會造成業務方不可接受的損失。
1)風險控制
騰訊游戲的實踐是每半年左右,在生產環境中做一次集中化的大規模混沌演練。更多的故障是在準生產環境(預發布環境)中進行。因為預發布環境與生產環境的配置基本相當,所以我們在準生產環境做實驗,數據的可靠性也有一定保證。
實踐過程中,我們發現很多問題都是在預發布環境中提前暴露的。我們在預發布環境發現了許多問題,這些問題都得到了提前的規避解決。
例如,游戲上都有體驗服大區,我們在體驗服中做實驗只影響體驗服的玩家,不會影響到現網的大批量玩家。所以一旦出問題,體驗服的玩家會反映服務有問題,我們就可以立馬發現系統的一些隱患。所以,我們很多的實踐都在預發布環境中進行。我們還進行了自動化的實踐,每次版本發布,我們會自動去執行混沌演練。
騰訊一般會有專門的演習環境,這個演習環境是跟現網完全隔離的,所有的人都可以在上面隨時隨地地發起混沌演練。這個演習環境非常方便我們的開發、測試以及運維同學去做演練。
目前來看,通過各個環境的管控,我們實驗風險得到了較好的控制。
2)實驗防護
光有實驗風險的控制是不夠的,我們希望有防護兜底的能力,包括我們的實驗防護能力。
實驗防護方面,我們的做法是基于穩態指標配置閾值。我們會采集業務的穩態指標,如果沒有的話,我們會提供Prometheus,讓用戶主動上報穩態指標。我們基于穩態指標配置閾值,指標達到閾值后會觸發告警,收到告警后會觸發一個鉤子,鉤子會終止實驗。這樣的話,在極端情況下,實驗就能夠做到自動終止,從而有效控制風險。
2、自動化實驗
上文中提到過游戲的版本,包括游戲商業化、活動部分,版本發布都非常快,可能隔一兩天就會發布一個活動。如果每發布一個活動或者每迭代一個版本都要做一次混沌實驗,成本會很高。所以我們把混沌實驗和我們的DevOps流水線集成起來,開發同學每發布一次版本都會自動調用混沌平臺的套餐去執行。這樣的話,無論每次在何時何地發布版本,實驗都會被自動地引用執行,大大降低了我們實驗的人力成本,提高了實驗效率。
3、紅藍對抗
做混沌工程的一個初衷是提升團隊的響應、協同效率,也就是我們組織的戰斗力。
事實上,一個團隊想提高自己的效率是缺乏動力的。騰訊游戲的做法是進行紅藍對抗,一個團隊對另外一個團隊的服務做攻擊、對抗,看這個團隊的服務可靠性到底如何,然后把它的攻擊結果在小的范圍內公示出來,這樣我們防守方自己的缺陷就會提前被暴露。紅藍對抗把混沌工程有效地在團隊之間進行了落地。將這種方式運轉起來,可以取得較好的收益。
4、實驗內容
我們做了一年多的混沌實驗,那么到底做了哪些實驗呢?下圖中抽象了一些具體的實驗項目。
每個業務、系統都有自己的特性,上圖中只是一些比較通用的項目。
1)單點故障
通過殺一臺機器、殺pod、殺容器,檢測故障隔離、準備切換、健康探針、探測等是否有效。
2)告警驗證
通過實驗觸發告警,看告警能不能被有效地處理,來檢測我們組織的響應機制。
3)強弱依賴
通過混沌工程發現強弱依賴不合理的關系。我們有時候會發現,一個配置管理端的故障可能導致現網的玩家訪問出現問題,控制面影響到數據面極不合理。我們通過混沌工程可以檢測到許多這種不合理的依賴關系,從而驗證我們服務架構的合理性。
4)網絡抖動
我們會經常在現網做一些網絡抖動實驗。用戶訪問我們的服務,鏈路是很長的,出現一些丟包、抖動是非常普遍的。所以測試我們的客戶端或者整個架構,到底能不能容忍網絡上的一些微小抖動,有沒有快速失敗、重試的策略,也是我們演練的一個重要目標。
5)機房故障
機房出現故障雖然是小概率事件,但還是有可能出現整個機房宕機、不可用的情況,我們要通過混沌工程去做一些整個機房不可用的實驗,驗證我們的服務是否具有異地容災的能力。
6)第三方故障
我們會使用第三方服務,它的質量可能不受我們掌控。這些第三方服務是否具備降級、熔斷這樣的一些策略,不可控的話,本地是否有緩存等,這些都可以通過混沌工程來驗證。
7)過載保護
一些黑產可能會對我們的服務進行一些惡意攻擊,我們的混沌工程可以模擬攻擊,主動去檢測我們的服務是否具備防刷、流控等能力。
以上是比較通用的一些實驗內容。當然每種業務都有自己的一些特性,這里不再一一贅述?;ヂ摼W行業變化是永恒的,我們的架構版本一直在變化,我們這個平臺也在不斷迭代。上述只是我們最近一年的一些初步的實踐經驗。
>>>>
Q&A
Q:混沌工程不斷地去制造故障,監控告警會不斷被觸發,你們是怎樣在很短的時間內終止操作的?不可控故障馬上自愈、監控馬上恢復的流程可以分享一下嗎?
A:這個點就是上面提到的實驗防護能力。我們平臺會采集包括業務的 QPS、延遲、同時在線人數等穩態指標。用戶在做實驗的時候,可以基于這些指標去配置告警閾值。比如我們的同時在線人數下降了20%,達到閾值,我們的故障防護策略就會生效。當然它不是立即的,可能會經過兩個或者三個周期,比如連續三個周期之后,它才會真正地觸發這一次實驗的防護,把實驗自動停止掉。