萬字長文:系統穩定性治理最佳實踐

前言

系統的穩定性,主要決定於整體的系統架構設計,然而也不可忽略程式設計的細節,正所謂“千里之堤,潰於蟻穴”,一旦考慮不周,看似無關緊要的程式碼片段可能會帶來整體軟體系統的崩潰。

穩定性的工作,一般都是水下的工作。就像冰山,真正強大的系統下,要有更加強大的底層支撐,水面下的問題才是真正需要解決的問題。當然不一樣的工作內容,水下的工作是不同的,對於蓋樓來說,可能就是地基的深度。對於我們寫業務邏輯來說,水下的工作就是CatchException的處理,異常情況的處理。對於系統來說,水下的工作可能是一些介面系統的穩定性。類似於金字塔結構,下層基礎決定上層建築。對於軟體系統來說,穩定性至關重要。

在開始介紹服務穩定性之前,我們先聊一下SLA。SLA(service-level agreement,即 服務級別協議)也稱服務等級協議,經常被用來衡量服務穩定性指標。通常被稱作“幾個9”,9越多代表服務全年可用時間越長服務也就越可靠,即停機時間越短。通常作為服務提供商與受服務使用者之間具體達成承諾的服務指標——質量、可用性,責任。

3個9,即99。9%,全年可停服務時間:365 * 24 * 60 *(1-99。9%)= 525。6min

4個9,即99。99%,全年可停服務時間:365 * 24 * 60 *(1-99。99%)= 52。56min

5個9,即99。999%,全年可停服務時間:365 * 24 * 60 *(1-99。999%)= 5。256min

在嚴苛的服務級別協議背後,其實是一些列規範要求來進行保障。

2021 年全球重大的系統事故,其中不乏亞馬遜、特斯拉、Facebook 等行業巨頭。

機構名稱

發生時間

持續時

影響範圍

原因

亞馬遜

2021年

12月

約3小時

全球亞馬遜雲計算服務

資料中心及網路連線問題

特斯拉

2021年

11月

約5小時

特斯拉 App 全球範圍

服務中斷

配置錯誤導致網路流量過載

Facebook

2021年

10月

約7小時

Facebook及旗下Messenger、Instagram、WhatsApp 等多個服務

運維操作失誤

嗶哩嗶哩

2021 年

7 月

約1小時

嗶哩嗶哩影片播放、

直播等多項服務

機房故障,災備系統失效

Fastly

2021 年

6 月

約1小時

包括亞馬遜、紐約時報、CNN 在內的登入網頁

系統漏洞被配置更改操作觸發

推特

2021 年

3 月

約2小時

登入失敗

系統內部錯誤

滴滴打車

2021 年

2 月

約1小時

滴滴打車 APP

系統內部錯誤

美聯儲

2021 年

2 月

約4小時

美聯儲大部分業務

操作失誤

何為系統穩定性

我們先看下百度百科對穩定性定義:

系統穩定性是指系統要素在外界影響下表現出的某種穩定狀態。

其次維基百科

對穩定性定義

穩定性是數學或工程上的用語,判別一系統在有界的輸入是否也產生有界的輸出。

若是,稱系統為穩定;若否,則稱系統為不穩定。

簡單理解,系統穩定性

本質上是系統的確定性應答

從另一個角度解釋,服務穩定性建設就是如何保障系統能夠滿足SLA所要求的服務等級協議。

Google SRE中(SRE三部曲[1])有一個層級模型來描述系統可靠性基礎和高層次需求(Dickerson‘s Hierarchy of Service Reliability),如下圖:

萬字長文:系統穩定性治理最佳實踐

該模型由Google SRE工程師Mikey Dickerson在2013年提出,將系統穩定性需求按照基礎程度進行了不同層次的體系化區分,形成穩定性標準金字塔模型。

金字塔的底座是監控(Monitoring),這是一個系統對於穩定性最基礎的要求,缺少監控的系統,如同蒙上眼睛狂奔的野馬,無從談及可控性,更遑論穩定性。更上層是應急響應(Incident Response),從一個問題被監控發現到最終解決,這期間的耗時直接取決於應急響應機制的成熟度。合理的應急策略能保證當故障發生時,所有問題能得到有序且妥善的處理,而不是慌亂成一鍋粥。事後總結以及根因分析(Postmortem&Root Caue Analysis),即我們平時談到的“覆盤”,雖然很多人都不太喜歡這項活動,但是不得不承認這是避免我們下次犯同樣錯誤的最有效手段,只有當摸清故障的根因以及對應的缺陷,我們才能對症下藥,合理進行規避。

假設一個系統從初次釋出後就不再進行更新迭代,做好上述三個方面的工作就能基本滿足系統對於穩定性的全部需求。可惜目前基本不會存在這樣的系統,大大小小的應用都離不開不斷的變更與釋出,因此要保證系統在這些迭代中持續穩定,測試和釋出管控(Testing&Release procedures)是必不可少的。有效的測試與釋出策略能保障系統所有新增變數都處於可控穩定區間內,從而達到整體服務終態穩定。除了程式碼邏輯更新,迭代同樣可能帶來業務規模及流量的變化,容量規劃(Capacity Planning)則是針對於這方面變化進行的保障策略。現有系統體量是否足夠支撐新的流量需求,整體鏈路上是否存在不對等的薄弱節點,都是容量規劃需要考慮的問題。

位於金字塔模型最頂端的是產品設計(Product)與軟體研發(Development),即透過優秀的產品設計與軟體設計使系統具備更高的可靠性,構建高可用產品架構體系,從而提升使用者體驗。

為了方便,本文闡述的系統主要指軟體系統。那麼如何衡量系統穩定性的高與低呢?一個常用的指標就是服務可用時長佔比,佔比越高說明系統穩定性也越高,如果我們拿一整年的資料來看,常見的 4 個 9(99。99%)意味著我們系統提供的服務全年的不可用時長只有 52 分鐘!它其實是一個綜合指標,為什麼這麼說?因為我們在服務可用的定義上會有一些差別,常見的服務可用包括:

服務無異常、服務響應時間低、服務有效(邏輯正確)、服務能正常觸發

等。

穩定性建設目標

架構設計源於生活,穩定性建設也肯定是源於生活,一般會把穩定性和消防放在一起進行比喻方便大家的理解,處理火災主要是階段:在火災前預防火災,在第一時間知道發生火災了,在發生火情的時候如何快速救火。透過火災處理對比軟體系統的穩定性,也就是預防(事前)、發現和處理(事中)了,最後(事後)我們加入了覆盤。發生問題不可怕,可怕的是已發生的問題重複發生。一定要杜絕有問題的事情第二次發生。

防火的最高境界是,防患於未然。這也就催生了,現代軟體系統裡面,大家把更多的精力放在事前(全鏈路壓測和故障演練方面)。

穩定性治理

影響穩定性的主要在兩個階段,一個階段是非執行期,一個階段是執行期。非執行期主要就是我們日常進行開發的時候,技術方案設計,程式碼書寫,線上操作配置等引發的穩定性問題。執行期主要是因服務自身問題、外部呼叫問題,外部依賴問題引發的穩定性,所以治理也主要從這兩個方面出發。

接下來會以上線前、上線中、上線後三個階段進行總結穩定性治理。

上線前

很多時候我們都以為系統穩定只是線上執行穩定就好了,但事實上需求研發流程是否規範,也會極大地影響到系統的穩定性。試想一下,如果誰都可以隨便提需求、做的功能沒有做方案設計、誰都可以直接操作線上伺服器,那麼這樣的系統服務能夠穩定得了嗎?所以說,需求上線前的過程也是影響系統穩定性的重大因素。

在我看來,在上線前這個階段,主要有三大塊非常重要的穩定性建設內容,分別是:

研發流程規範

釋出流程規範

高可用架構設計

萬字長文:系統穩定性治理最佳實踐

研發流程規範

研發流程規範,指的是一個需求從提出到完成的整個過程應該是怎樣流轉的。一般的需求研發流程包括:產品提出需求、技術預研、需求評審、技術方案設計、測試用例評審、技術方案評審、測試用例評審、需求開發、程式碼評審、需求測試。不同公司根據情況會有所調整,但大差不差。

萬字長文:系統穩定性治理最佳實踐

在這個流程中,與研發相關的幾個比較重要的節點是:技術方案設計及評審、測試用例評審及評審、需求開發、程式碼測試覆蓋率、程式碼評審。我們上面提到的幾個影響穩定性的因素,就是因為沒有做好這幾個節點的工作導致的,包括:

未測試需求直接上線

上線的需求產品不知道

上線的新需求有 bug

上線後沒有線上驗證

系統設計方案存在缺陷

系統程式碼實現存在缺陷

如果能夠處理好上述幾個節點,那麼就能夠極大地降低研發流程導致的問題。這裡每個節點都有很深的學問,這裡就不展開講了,我們主要說個思路。

研發團隊最希望拿到的需求是真正有業務價值的需求,而不是一個短期或臨時的需求,因為如果是一個臨時需求的話,往往對應的解決方案也是臨時的,如果太多臨時的解決方案遺留在系統中,久而久之將會變成巨大的“技術債”,總有一天會爆發,對系統穩定性及業務迭代速度造成巨大影響。

另外有一點比較重要的是,透過需求評審,不僅僅是評審產品業務需求,更重要的是需要研發挖掘出一些非功能需求,包括效能指標要求、依賴三方介面qps、安全等要求。

對於編碼規範、技術方案評審、程式碼評審、釋出計劃評審,這裡重點講一下這四點。

編碼規範

對外介面命名方式、統一異常父類、業務異常碼規範、對外提供服務不可用是拋異常還是返回錯誤碼、統一第三方庫的版本、哪些場景必須使用內部公共庫、埋點日誌怎麼打、提供統一的日誌、監控切面實現等,編碼規範除了能規範開發的編碼行為、避免犯一些低階錯誤和踩一些重複的坑外,另一個好處是讓新入職的同學能快速瞭解公司的編碼原則,這點對編碼快速上手很重要,更多可以參考阿里巴巴的Java開發規範。

技術方案評審

再也沒有比糟糕的設計更有破壞力的東西了,技術方案設計評審和 CR 可以放在一起做,先評審設計再進行 CR,有人就會說,都編碼完了才進行設計評審是不是晚了?其實這要看情況而定,如果團隊內部經常產出“糟糕設計”,那麼我覺得設計評審就應該編碼之前來做,但如果團隊成員專業能力和經驗都還不錯,那麼我們允許你再編碼之後再做設計評審,而且編碼的過程其實也是設計的過程,可以規避提前設計而導致後續編碼和設計不一致的問題。設計評審的原則是,既要講最終的設計方案,也要講你淘汰的設計方案!

關於如何寫技術方案以及評審更多細節,可以參考我之前公眾號寫的文章

《如何寫好&評審一份技術方案》

Farley1005,公眾號:網際網路技術集中營如何寫好&評審一份技術方案

程式碼評審

程式碼質量包括功能性程式碼質量和非功能性程式碼質量,功能質量大多透過測試能夠去發現問題,非功能性程式碼質量使用者不能直接體驗到這種質量的好壞,程式碼質量不好,最直接的“受害者”是開發者或組織自身,因為程式碼質量好壞直接決定了軟體的可維護性成本的高低。程式碼質量應該更多的應該從可測性,可讀性,可理解性,容變性等程式碼可維護性維度去衡量,其中 CodeReview 是保證程式碼質量非常重要的一個環節,建立良好的 CodeReview 規範與習慣,對於一個技術團隊是一件非常重要核心的事情,沒有 CodeReview 的團隊沒有未來。

每次專案開發自測完成後,通常會組織該小組開發人員集體進行程式碼 review,程式碼 review 一般 review 程式碼質量以及規範方面的問題,另外需要關注的是每一行程式碼變更是否與本次需求相關,如果存在搭車釋出或者程式碼重構最佳化,需要自行保證測試透過,否則不予釋出。

關於如何做好程式碼評審細節,更多可以參考我之前寫的公眾號文章

《如何做好codereview》

孔凡勇,公眾號:網際網路技術集中營如何做好CodeReview

釋出計劃評審

涉及到10人日以上的專案,必須有明確的釋出計劃,並組織專案成員統一參加專案釋出計劃 review,釋出計劃主要包含如下幾點:

1)明確是否有外部依賴介面,如有請同步協調好業務方;

2)釋出前配置確認包括配置檔案、資料庫配置、中介軟體配置等各種配置,尤其各種環境下的差異化配置項;

3)二方庫釋出順序,是否有依賴;

4)應用釋出順序;

5)資料庫是否有資料變更和訂正,以及表結構調整;

6)回滾計劃,必須要有回滾計劃,釋出出現問題要有緊急回滾策略;

7)生產環境迴歸測試重點 Case。

釋出流程規範

釋出流程規範主要是為了控制釋出許可權以及釋出頻率的問題。

在專案初始,為了快速響應業務,一般許可權控制都很鬆,很多人都可以進行線上服務的釋出。但隨著業務越來越多、流量越來越大,相對應的故障也越來越多,到了某個時候就需要對許可權做管控,並且需要對需求的釋出頻率做控制。

對於需求釋出流程來說,一般有幾種釋出方式,分別是:Release Train 方式、零散發布方式。Release Train 意思是固定時間視窗釋出,例如每週四釋出一次。如果無法趕上這次釋出時間,那麼就需要等到下次釋出視窗。零散發布方式,指的是有需要就釋出,不做釋出時間控制。但這種方式一般只在專案初期發揮作用,後期一般都會收緊。

除此之外,釋出流程中都會設有緊急釋出流程,即如果某個需求特別重要,或者有緊急漏洞需要修復,那麼可以透過該流程來緊急修復,從而避免因未到時間視窗而對業務產生影響。但一般來說,緊急釋出流程都比較麻煩,除非迫不得已不然不要審批透過,不然 Release Train 方式可能會退化成零散發布方式。

高可用架構設計

高可用架構設計指的是為了讓系統在各種異常情況下都能正常工作,從而使得系統更加穩定。其實這塊應該是屬於研發流程規範中的技術方案設計的,但研發流程規範更加註重於規範,高可用設計更加註重高可用。另外,也由於高可用設計是非常重要,因此獨立拿出來作為一塊來說說。

對於高可用設計來說,一般可分為兩大塊,分別是:服務治理和容災設計。

萬字長文:系統穩定性治理最佳實踐

服務治理就包括了限流、降級、熔斷、隔離等,這一些考慮點都是為了讓系統在某些特殊情況下,都能穩定工作。例如限流是為了在上游請求量太大的時候,系統不至於被巨大的流量擊垮,還可以正常提供服務。服務治理這塊像SpringCloud Alibaba都有標準的成熟解決方案,比如可以基於sentinel實現限流、降級、熔斷、隔離,隔離可以實現執行緒池隔離和訊號量隔離,這裡不再做詳細介紹。

容災設計應該說是更加高階點的設計了,指的是當下遊系、第三方、中介軟體掛了,如何保證系統還能正常執行?可以說容災設計比起服務治理,其面臨的情況更加糟糕。例如支付系統最終是透過 A 服務商進行支付的,如果 A 服務商突然掛了,那我們的支付系統是不是就掛了?那有什麼辦法可以在這種情況(災難)發生的時候,讓我們的系統還能夠正常提供服務呢?這就是容災設計需要做的事情了,接下來將重點介紹一些容災設計方案。

消除單點

從請求發起側到服務處理返回的呼叫全鏈路的各個環節上避免存在單點(某個環節只由單個伺服器完成功能),做到每個環節使用相互獨立的多臺伺服器進行分散式處理,要針對不同穩定性要求級別和成本能力做到不同伺服器規模分散式,這樣就避免單個伺服器掛掉引發單點故障後進而導致服務整體掛掉的風險。可能涉及的環節有端動態獲取資源服務(html& js &小程式包等)、域名解析、多服務商多區域多機房IP入口、靜態資源服務、接入路由層、服務邏輯層、任務排程執行層、依賴的微服務、資料庫及訊息中介軟體。

冗餘依賴,消除單點的策略:

在服務邏輯層採用多運營商多IP入口、跨地&同地多機房部署、同機房多機器部署、分散式任務排程等策略。

在資料儲存層採用資料庫分庫分表、資料庫主從備叢集、KV儲存&訊息等分散式系統叢集多副本等策略。

有分散式處理能力後,需要考慮單個伺服器故障後自動探活摘除、伺服器增刪能不停服自動同步給依賴方等問題,這裡就需引入一些分散式中樞控制系統,如服務註冊發現系統、配置變更系統等,例如zookeeper是一個經典應用於該場景的一個分散式元件。

冗餘設計

冗餘設計,對於飛機而言,體現在機組包括機長副機長,引擎至少雙發,作業系統至少兩套等等,於我們的系統而言,則通常體現在:

資料冗餘,資料多份副本,DB 一主多備,出現問題時可以快速切換。

計算能力冗餘,伺服器的計算能力始終保持一定冗餘,在一組伺服器出現問題時其他伺服器可以接替提供服務,亦或在業務量波動時可以承受衝擊。

網路,儲存或其他基礎設施冗餘,出現意外時,比如斷電,光纖斷裂時均有備用可以實現切換,快速恢復。

冗餘設計這塊直接延伸出來的異地多活方案,更多詳細的設計可以參考我之前寫的公眾號文章

《高可用容災架構設計》

孔凡勇,公眾號:網際網路技術集中營高可用容災架構演進之路

強弱依賴

當服務依賴各類微服務時,避免強依賴(依賴服務掛掉會到自己服務掛掉),儘可能在對應服務出現問題時做到自動降級處理(弱依賴)或者手工降級,降級後依賴服務功能區域性去掉或做合適區域性提示,區域性體驗上有部分降級,但不會讓主鏈路和整體功能掛掉。對於穩定性要求很好的關鍵系統,在成本可接受的情況下,同時維護一套保障主鏈路可用的備用系統和架構,在核心依賴服務出現問題能做一定時間週期的切換過渡(例如mysql故障,階段性使用KV資料庫等)。

強依賴的服務越少,系統整體基礎穩定性就越高。部分特殊資料依賴多於邏輯依賴的系統,做去依賴架構設計也是一個思路,將依賴服務資料統一整合到自有服務的資料儲存中,透過訊息 或定時更新的方式更新,做到不依賴 或少依賴其他系統,進而提高穩定性,但這樣做也會有副作用:資料冗餘可能會引發不同程度一定時間視窗資料不一致性。

熱點極限值處理

業務規模以及資料規模大的部分系統,在系統中會出現資料熱點、資料極度傾斜、少量大客戶超過極限閾值使用等極限場景,例如超級大客戶廣告投放物料、廣告點選展示資料、API呼叫頻次都是比普通客戶大很多,如果按照客戶維度分庫分表,基本在物料更新、查詢、報表檢視等一系列的場景都可能導致單庫抖動,這除了影響大客戶自己外也會影響分佈在該分庫分表上所有普通客戶。電商中極度暢銷商品以及秒殺、微博等訂閱類明星大V的資訊釋出等都是少量極限場景可能會引發整體系統穩定性問題。因此,架構設計時,要分析自己系統中是否存在極限場景並設計對應方案做好應對。

極限場景中不同型別場景處理架構方案也不一樣,可能的方式:

大客戶從普通客戶分庫分表中拆出來隔離建庫表,隔離享用專有資源以及獨立庫表拆分路由邏輯以及隔離服務邏輯計算資源;

大客戶特定極限資料計算做預約計算以及預載入,在低峰期預約或提前最佳化完成;

秒殺系統極限值可以考慮核心邏輯簡化+訊息解耦、同商品庫存拆分獨立交易、部分查詢或處理KV儲存替代關係型儲存、資料提前預熱載入、排隊、限流策略等策略;

在特定極限值系統架構以及資源無法滿足的情況,產品側以及技術側要明確採用最高閾值呼叫限制。

資損風險

交易系統對於資料準確性、一致性、資金損失等都是很敏感的,這一塊在是否使用快取、事務一致性考量、資料時延、資料不丟不重、資料精準核對和恢復等需要額外架構設計考量。仔細評估交易以及營銷的全鏈路各個環節,評估其中出現資損的可能性以及做好應對設計,例如增加多層級對賬、券總額度控制、異常金額限制和報警等資損防控的考量等。不同層次不同維度不同時間延遲的對賬以及預案是一個重要及時感知資損和止血的有效方式。全鏈路的過程資料要做好儘可能持久化和冗餘備份,方便後續核對以及基於過程資料進行資料修復,同時儘量針對特殊資料丟失場景提供快速自動化修復處理預案(如交易訊息可選擇性回放和基於冪等原則的重新消費)。

彈性處理

訊息重複消費、介面重複呼叫對應的服務是否保證冪等?是否考慮了服務降級?哪些業務支援降級?支援自動降級還是手工降級?是否考慮了服務的超時熔斷、異常熔斷、限流熔斷?觸發熔斷後對客戶的影響?服務是否做了隔離,單一服務故障是否影響全域性?這些問題統統需要我們想清楚對應的解決方案,才會進一步保證架構設計的合理性。

相容性

上下游依賴是否梳理過,影響範圍多大?怎麼進行新老系統替換?新老系統能否來回切換?資料儲存是否相容老的資料處理?如果對你的上下游系統有影響,是否通知到上下游業務方?上下游依賴方進行升級的方案成本如何最小化?這些問題需要有完美的解決方案,稍有不慎會導致故障。

安全性

是否徹底避免 SQL 注入和 XSS?是否有資料洩露的可能性?是否做了風控策略?介面服務是否有防刷保護機制?資料、功能許可權是否做了控制?小二後臺系統是否做了日誌審計?資料傳輸是否加密驗籤?應用程式碼中是否有明文的 AK/SK、密碼?這些安全細節問題需要我們統統考慮清楚,安全問題任何時候都不能輕視。

其他異常情況

整體系統架構高可用還需要考慮可測性、可運維性,除了正向邏輯、效能、擴充套件性設計等外,要增加一個異常設計視角,窮盡思考各類異常情況以及設計應對策略。

容量評估

系統設計整體至少考慮應對5到10倍或近1到3年系統規模增長,要保障後續透過增加機器資源等快速方式能實現系統水平擴容。例如分庫分表的規模提前設計好提前量,避免臨時資料庫能力不足導致需要臨時重構擴容(增加分庫分表以及修改路由以及遷移資料);服務邏輯層設計持有資料狀態導致無法加機器做服務層擴容。網際網路產品發展變化較快,不一定會如期爆發,容量架構設計上也要注意不要過度提前設計,避擴音前複雜化引發研發效率以及機器成本問題。

針對線上流量峰值,建議系統常態保持近期峰值3倍左右容量餘量,上線前和上線後要定期做壓測摸高,寫流量可用影子表等方式做壓測,壓測可單介面以及模擬線上流量分佈壓測結合,根據壓測結果最佳化架構或擴容,持續保持容量富餘。

對於可能超過系統現有容量的突發峰值,限流策略是線上要配置的策略。入口側入口流量呼叫 、不同渠道服務依賴呼叫、對依賴服務的呼叫都要評估可極限調研的上限值,透過中介軟體等合適方式限制超過閾值呼叫,避免引發雪崩效應。特定業務系統,對於超過峰值流量,可以透過訊息架構以及合適體驗設計做削峰填谷。針對惡意攻擊流量也要考慮在入口層部署防DDOS攻擊的流量清洗層。

部分系統峰值變化較大且需要持續儘可能承載保障,可考慮引入彈性伸縮策略,預約 或根據流量變化觸發系統自動擴縮容,以確保以儘量小成本來自動化滿足變化峰值。

上線中

上線時這個階段,主要是確保功能按照原先設計的方案進行部署,這個階段主要是確保規範操作,避免失誤,因此可以制定相關的 CheckList 以及變更審批。其次,為了避免還可能存在未發現的功能缺陷,有時候還可以使用灰度釋出降低風險。在這個階段能做的一些穩定性建設如下圖所示。

萬字長文:系統穩定性治理最佳實踐

對於釋出前的checklist更多可以參考前面所講的釋出計劃,釋出後的checklist更多的需要根據測試提供的測試用例進行生產環境迴歸測試驗證。

這裡涉及到的變更審批非常關鍵,根據實際情況,有些審批可以提前提交申請。

灰度保障及時在小流量情況,發現問題,避免引發大範圍故障。因此在做系統任何變更時,要考慮灰度方案,特別是大使用者流量系統。灰度方式可能有白名單使用者、按使用者Id固定劃分後不同流量比例、機器分批發布、業務概念相關分組分比例(例如某個行業、某個商品、某類商品)等,灰度週期要和結合系統風險和流量做合適設計,重要系統灰度週期可能持續超過一週或更多。

關於灰度釋出更多細節,可以參考我之前公眾號寫的文章《灰度釋出架構設計終極篇》。

上線後

當系統成功上線後,很多小夥伴以為工作就結束了,但實際上我們還有不少工作可以做。根據我的經驗,在上線後我們能做的穩定性建設包括:

監控報警

故障管理

緊急預案

故障容災演練

案例學習

全鏈路壓測

全鏈路跟蹤

萬字長文:系統穩定性治理最佳實踐

監控告警

監控報警,指的是我們需要對應用做好執行資料的收集,監控好系統的執行狀態。當系統狀態異常時,我們需要及時地發現並報警,從而讓研發人員快速地解決問題。一般來說,監控報警分為系統級別的監控報警和業務級別的監控報警。系統級別的監控報警包括 CPU、記憶體、磁碟等伺服器資源的監控,而業務級別的報警則需要根據業務情況自行定義。

故障容災演練

故障容災演練需要從已知、半已知和未知三個維度去做。

已知:已知故障型別,按照應急預案SOP,一步一步去做,從生疏到熟練,從20分鐘到5分鐘,從有限的人能做變成所有人能做。

半已知:在已知故障型別的演練中,發現了未知因素,如:當快取叢集故障的時候,切換到備用快取叢集,但發現備用快取集群裡面的快取資料有問題,需要重新清空及重新進行快取預熱。

未知:未知故障型別,臨時決策安排人員有序散開排查,臨時根據現象定位問題,採用回滾版本或者重啟等方式嘗試性解決問題,或定位到問題後,採用有損的方式試圖臨時解決問題等。

故障容災演練是提升系統穩定性的一把利器,很多時候即使我們設計得很完美,但實際上卻沒發揮作用,究其根本就是沒有實踐過。是驢是馬,得拉出來溜溜才知道。

故障管理

故障管理,就是當發生故障時,我們需要遵循的整套處理規範。

團隊小的時候可能無所謂,但是當團隊大了的時候,我們就需要統一大家的故障處理流程,從而可以更快速地解決故障。此外,在故障解決完成之後還需要進行復盤,產出對應的故障報告。

Case Study

Case Study 機制指的是定期學習其他團隊的高可用或者線上故障進行學習,從而提高團隊的系統設計能力,避免踩坑。

緊急預案

緊急處理預案,簡單就是要想到各種可能發現的情況,然後做好預案。之後結合容災演練不斷進行最佳化,從而形成一套很好的處理預案。這樣當線上發生類似故障時,就可以輕鬆應對了。

在發生故障的時候,大多數人的腦子都是一片空白,很難迅速做出最合理的反應。衡量一個應急預案的好壞,關鍵是看它是否足夠“無腦化”。

舉個例子:如果發現了故障A,那麼我們需要排查B和C兩個方面來精準定位問題,定位後,我們再透過D—>E—>F三個操作來解決問題。

即:整個過程中,只需要照做,不需要思考,因為思考就會產生選擇,而選擇取捨是最耗費時間的事情,如果做不到這點,那麼證明應急預案還有最佳化的空間。

另外,預案也不是一蹴而就的事情,需要跟隨架構和業務的演進,不斷進行更新迭代,同時,也需要不斷做減法,該摒棄的摒棄,該合併的合併,如果只增不減,那麼一年以後,預案就會變成一本書。

緊急預案一般要包含如下內容:

故障發生時應該通知哪些人或團隊。

如何選出協調者,什麼情況下該選出協調者。

協調者的職責有哪些。

需要操作開關時,誰有權利決策。

常見故障以及對應的止損方式。

止損的原則是什麼,什麼是最重要的。善後方案誰來拍板。

預案很重要,完備的預案能降低故障定位和止損的時間,提升協作效率。

自動防禦

這是件很能體現出工程師能力和素養的事情,需要工程師在coding過程中,在任何關鍵環節都具備安全意識。如:

當下遊依賴的儲存叢集,由於不可用而觸發程式碼中的失敗次數或失敗時間閾值時,自動切換到備用的儲存叢集。

當下遊依賴的核心服務,由於不可用而觸發程式碼中的失敗次數或失敗時間閾值時,自動降級到備用方案,如:將請求切換到儲存非實時資料的ES中,接受有損。

當系統由於響應時間激增而導致服務不可用時,自動對下游依賴的非核心服務進行降級熔斷,減少服務介面的整體響應時間,保證可用。

全鏈路壓測

全鏈路壓測,指的是對整個鏈路進行壓測。不同公司可能會採用不同的方案,有些會直接在線上進行壓測,然後用流量標記的方式識別測試流量。有些則是進行流量錄製,之後重新搭建一套與線上非常類似的系統進行壓測。一般來說,第一種效果肯定會更好,成本也更低,但是對研發人員要求也更高,風險也更大。比如阿里天貓每年雙11都會進行全鏈路壓測,基於線上流量回放機制。

全鏈路跟蹤

全鏈路跟蹤是生產環境問題排查利器,開源的有skywalking,阿里內部對應的是eagleeye,能夠根據請求traceid,快速診斷出生產環境bug。

技術團隊文化

人的意識是最重要的,專業能力可以鍛鍊培養。如果意識不足或鬆懈,好的能力以及機制流程也會形同虛設。

永遠要對敬畏線上,敬畏客戶體驗。面向線上的穩定性戰術上可以基於專業度鍛鍊後自信,但戰略和思想上必須持續如履薄冰、三省吾身。線上穩定性保障是作為技術人自己專業度的追求和必須保持初心,始終保持敬畏。不因為業務繁忙、個人心情狀態、團隊是否重視而有變化,只要職責在,就要守護好。技術主管以及系統owner要有持續感知穩定性隱患和風險,保持銳度,集中性以及系統性查差補漏。

團隊工作規範

日常巡檢

為什麼要把系統健康度巡檢放到技術管理裡,我覺得這是一個非常重要的環節。像傳統的航空、電力、汽車行業都要有一定的巡檢機制,保障裝置系統正常運轉,同樣軟體系統也同樣需要巡檢機制保障業務健康發展。

隨著業務的不斷髮展,業務量和資料量不斷的上漲,系統架構的腐蝕是避免不了的,為了保障系統的健康度,需要不斷的考慮對系統架構、效能進行最佳化。

系統的監控與報警能夠一定程度發現系統存在的問題,系統存在的一些隱患需要透過對系統的巡檢去發現,如果最佳化不及時在極端情況會導致故障,巡檢粒度建議每週巡檢一次自己所負責的業務系統。

系統巡檢重點要關注如下幾點:

系統指標

:系統 CPU、負載、記憶體、網路、磁碟有無異常情況波動,確認是否由釋出導致,還是系統呼叫異常。

慢介面:

通常 RT 大於3s的介面需要重點關注,極端併發場景下容易導致整個系統雪崩。

慢查詢:

MySQL 慢查詢需要重點關注,隨著資料量上漲,需要對慢查詢進行最佳化。

錯誤日誌:

透過錯誤日誌去發現系統隱藏的一些 BUG,避免這些 BUG 被放大,甚至極端情況下會導致故障。

每個報警不要放過,每個報警及時響應處理

快速定位和快速恢復是個人以及團隊專業能力沉澱,但快速報警響應是每個敬畏線上敬畏使用者體驗的技術同學可以做到的。

在監控完備和持續前提下,每個報警及時處理即可以降低故障影響範圍,也會持續減少小的隱患。報警一些小的實踐技巧:報警按照方向收斂報警群,建立報警天級值班機制,報警簡訊手機設定為震動模式(不打擾同空間家人或朋友情況下,自己第一時間感知),主管要訂閱報警作為團隊報警兜底處理人,報警響應好的同學和不好的同學要資料化表揚和批評。

從團隊角度,報警及時響應必須配合報警治理進行,否則過多無效報警也會讓有責任心的同學變得麻木。所以必須控制無效報警的數量,例如單應用無效報警(不需要線上問題進行定位以及修復處理的)不要超過5條,個人維度無效報警天級別不超過10條。

線上問題要覆盤,不論是否為定級故障,不論問題大小

小的線上問題也要覆盤,覆盤準備度可以低於定級故障,但都需要思考反思以及落實最佳化Action。小的線上問題就是未來線上故障的前兆。我們團隊週會上都會有一個環節,上週如有線上問題則會安排對觸發人做覆盤。

每個使用者反饋要重視,定位到根本原因

一個使用者反饋背後必然有多個實際線上問題,只是這個使用者無法忍受,知道反饋路徑以及對這個產品有熱愛 或強依賴才選擇反饋的。徹底定位一個voc,就是修復了一類線上問題。而且到使用者反饋的程度,這個線上問題就已經有一定程度使用者體驗影響了。我們現在技術團隊有一個voc日清機制,針對線上voc問題對使用者做好日內響應答覆,也是一個不錯對於這個意識的數字化衡量。

人員能力培養

單個技術同學個人技術以及穩定性保障能力是團隊在每個穩定性任務上拿到結果的執行者和基礎,因此技術主管重視識別不同同學個人優勢和不足,針對性做工作安排以及培養鍛鍊。只要線上意識上足夠重視,能力對於大部門技術同學是可以培養的。

團隊內同學由於入行時間、歷史經驗等各方面原因,對於當前系統穩定性保障能力是有強弱的差異的,對於個人是正常情況,但對於團隊而言,不能因為團隊個別同學能力上存在不足而引入團隊層面穩定性保障風險。需要主管很好熟悉以及判斷同學能力段位,在負責系統和模組、流程機制約束、輔導人等方面做好差異化安排。例如校招同學X個月不做線上釋出,前X個月釋出有師兄協同釋出機制,併發高 或資金交易等等風險高的系統讓更加有經驗的負責。同時設計培養機制,能力當前不足但有潛力的同學,可以安排由經驗豐富的同學指導以及提供一些進階實操路徑,按照節奏從易到難逐漸承擔更高風險的系統職責。

能力培養方式有技術Review、程式碼CR和輔導、參與團隊穩定性保障機制、安排合適師兄指導、過程中主管指導、逐漸承擔更高職責等。程式碼層面,對於Java同學來說, 《阿里巴巴Java開發手冊》是一個很好的實踐性指南,超出程式碼風格,提供了日誌、異常處理、集合等庫使用、資料庫設計、分層設計等多個提升程式碼質量的實踐做法,我們自己團隊所有Java研發同學都會100%透過阿里雲上阿里巴巴程式碼認證考試,同時團隊有一個團隊內新人品碼機制,這些都是不錯地培養同學寫出好程式碼的培養方式。

好多小團隊、大團隊、公司都有很多不錯提升穩定性機制和案例,積極主動參考學習以及結合自己業務系統思考踐行,是自己提升重要路徑。架構上高可用以及架構相關經典書籍自我學習,從理論上做系統性認知也是有必要。

總結

在軟體架構上有一句名言,沒有最完美的架構,只有最適合的架構。推廣到穩定性上,沒有完全完美的穩定性方案,只有適合的穩定性方案。

系統穩定性壓倒一切,只有保障了好了穩定性,才能幫助業務蓬勃增長,因此穩定性治理始終是工程師基本能力之一。

穩定性建設是一個系統的基石,也是一個持續的過程,面對業務的不同發展階段,對穩定性的落地要求不同,取捨也不同(適合的才是最好的~),但隨著業務發展,佔比越來越大,關注點也會越來越高。