本文是Uber 的工程師Gergely Orosz 的文章,原文網址在:https://blog.pragmaticengineer.com/operating-a-high-scale-distributed-system/
#在過去的幾年裡,我一直在建造和運營一個大型分散式系統:優步的支付系統。在此期間,我學到了很多關於分散式架構概念的知識,並親眼目睹了高負載和高可用性系統運行的挑戰(一個系統遠遠不是開發完了就完了,線上運行的挑戰實際上更大)。建構系統本身是一項有趣的工作。規劃系統如何處理10x / 100x流量的增加,確保資料持久,面對硬體故障處理等等,這些都需要智慧。不管怎樣,維運大型分散式系統對我來說是個令人大開眼界的體驗。
系統越大,墨菲的「什麼可能出錯,就會出錯」的定律就越會體現。頻繁部署、部署程式碼的開發人員數量很多,涉及多個資料中心、系統被大量全球使用者使用,這種出錯機率越大。在過去的幾年裡,我經歷過各種各樣的系統故障,其中很多讓我感到驚訝。有些來自可預測的事情,例如硬體故障或一些看起來無害的Bug,還有資料中心線纜被挖斷、同時發生多個級聯故障。我經歷了數十次業務停擺,系統的某些部分無法正常運作,導致巨大的業務影響。
這篇文章是我在Uber工作時總結的,可以有效運作大型系統的實踐的集合。我的經驗並不是獨一無二的 - 在類似規模的系統上工作的人也經歷了類似的旅程。我與Google,Facebook和Netflix的工程師進行了交談,他們分享了類似的經驗和解決方案。這裡列出的許多想法和流程應該適用於類似規模的系統,無論是在自己的資料中心(如Uber大多數情況下)上運行,還是在雲端上運行(Uber 有時會把部分服務彈性部署到雲端上)。但是,對於規模較小或較少關鍵任務的系統而言,這些做法可能過於苛刻。
涉及的內容很多——我將討論以下主題:
要知道系統是否健康,我們需要回答“我的系統是否正常運作」的問題?為此,收集系統關鍵部分的數據至關重要。對於在多台電腦和資料中心上執行多個服務的分散式系統,可能很難確定要監控的關鍵內容是什麼。
基礎設施健康監測 如果一個或多個電腦/虛擬機器過載,則分散式系統的某些部分可能會降級。機器的健康狀況,CPU利用率、記憶體使用情況,是值得監控的基礎內容。有些平台可以開箱即用地處理這種監控和自動擴展實例。在優步,我們擁有一支優秀的核心基礎設施團隊,提供開箱即用的基礎設施監控和警報。不管技術層面如何實現,實例或基礎設施出問題的時候,監控平台需要提供必要的資訊。
服務運作狀況監控:流量,錯誤,延遲。我們經常需要回答「這個後端服務是否健康?」這樣的問題。觀察存取端點的請求流量、錯誤率和端點延遲等事項都可以提供有關服務健康狀況的有價值資訊。我更喜歡將這些都顯示在儀表板上。在建立新服務時,透過使用正確的HTTP回應映射並監視相關程式碼可以對系統有很多了解。因此,確保客戶端錯誤能回傳4XX,以及如果伺服器錯誤則回傳5xx,這種監控易於建置且易於解釋。
監控延遲值得再考慮一下。對於生產服務,目標是讓大多數最終用戶獲得良好的體驗。事實證明,測量平均延遲並不是一個很好的指標,因為這個平均值可以隱藏一小部分高延遲請求。測量p95,p99或p999 - 第95百分位,第99百分位或第99.9百分位的請求所經歷的延遲 - 是一個更好的指標。這些數字有助於回答諸如「99%的人的請求有多快?」之類的問題(p99)。或 “1000人中,至少有一人經歷了多慢的延遲?” (p999)。對於那些對這個主題更感興趣的人,這篇延遲入門文章可以進一步閱讀。
從圖上可以明顯看出,平均延遲、p95、p99 差異還是比較大的。所以平均延遲有可能掩蓋一些問題。
圍繞監控和可觀察性有很多更有深度的內容。值得一讀的兩個資源是Google的SRE書和關於分散式系統監控的四個黃金指標的部分。他們建議,如果您只能測量面向使用者的系統的四個指標,請注意流量,錯誤,延遲和飽和度。比較簡短的資料的話,推薦來自Cindy Sridharan的分散式系統可觀察性電子書,它涉及其他有用的工具,如事件日誌,指標和追蹤最佳實踐。
業務指標監控。監控服務模組,可以告訴我們服務模組運作的如何如何正常,但無法告知我們業務是否按預期工作,是否「照常營業」。在支付系統,一個關鍵問題是,「人們可以使用特定的支付方式進行支付業務嗎?」。識別業務事件並對其監控,是最重要的監控步驟之一。
雖然我們建立了各種監控,有些業務問題仍然無法偵測到,這讓我們遭受了巨大的痛苦,最終建立了業務指標的監控。有時我們所有的服務看起來都正常運行,但關鍵產品功能不可用!這種監控對我們的組織和領域來說非常有用。因此,我們必須在Uber的可觀察性技術堆疊的基礎上,為自己定制這種類型的監控做了大量的思考和努力。
譯者註:業務指標監控這一點,我們實在是太深有同感了,之前在滴滴有時就是發現所有服務都正常,但是業務不好使。我們現在創業做的北極星系統,就是專門處理這個問題的。有興趣的朋友可以在公眾號後台給我留言,或加我好友 picobyte 交流試用。
監控對於洞察系統的當前狀態而言,是一個很棒的工具。但這只是自動檢測問題並發出警報以供人們採取行動的一個墊腳石。
Oncall 本身是一個廣泛的話題 - Increment 雜誌在其 “On-Call 問題”中涵蓋了許多方面的內容。我的強烈認為,如果你擁有了"you build it, you own it"的心態,那隨著而來的就是 OnCall。建構服務的團隊擁有這些服務,也負責值班。我們的團隊負責支付服務的值班。因此,每當出現警報時,值班工程師都會回應並查看詳細資訊。但是要如何從監控到警報呢?
從監控資料中偵測異常是一個艱鉅的挑戰,也是機器學習可以發光的領域。有很多第三方服務提供異常檢測。再次幸運的是,我們團隊有一個內部機器學習團隊與之合作,他們根據Uber的使用情況量身定制了解決方案。位於紐約的 Observability 團隊撰寫了一篇有用的文章,介紹 Uber 的異常檢測工作原理。從我的團隊的角度來看,我們將監控數據推送到該團隊的管道,並獲得具有各自置信度的警報。然後我們決定是否應該打電話給工程師。
何時觸發警報是一個有趣的問題。警報太少可能意味著錯過有影響的中斷。太多會導致不眠之夜並使人筋疲力盡。追蹤和分類警報以及測量信噪比對於調整警報系統至關重要。檢查警報並標記它們是否可操作,然後採取措施減少不可操作的警報,這是朝著實現可持續的隨叫隨到的良好一步。
Uber 使用的內部 oncall 儀表板範例,由 Vilnius 的 Uber 開發人員體驗團隊建立。
位於 Vilnius 的Uber開發工具團隊建立了整潔的通話工具,我們用它來註解警報並視覺化呼叫班次。我們的團隊每週對上一次值班班次進行回顧,分析痛點並花時間改善值班體驗,一周又一周。
譯者註:告警事件的聚合、降噪、排班、認領、升級、協同、靈活的推送策略、多渠道推送、和IM打通,是很通用的需求,可以參考 FlashDuty 這個產品,體驗地址:https://console.flashcat.cloud/
想像一下:你是本週的值班工程師。半夜,一個警報把你吵醒了。你調查是否有生產中斷發生。糟糕,似乎系統的某個部分出現了故障。現在怎麼辦?監控和警報真實發生了。
對於小型系統來說,中斷可能不是什麼大問題,值班工程師可以了解正在發生的事情以及原因。它們通常易於理解且易於緩解。對於具有多個(微)服務的複雜系統,許多工程師將程式碼推向生產,僅僅找出潛在問題發生的位置就已經足夠具有挑戰性了。有一些標準流程來幫助解決這個問題會產生巨大的改觀。
附加到警報的Runbook手冊,描述簡單的緩解步驟是第一道防線。對於擁有良好Runbook手冊的團隊,即使值班工程師不深入了解系統,也很少會成為問題。 Runbook 需要保持最新、更新,並在故障出現時使用新型緩解措施進行處理。
譯者註:Nightingale 和Grafana 的警告規則配置中,可以支援自訂字段,但是有些附加字段是預設就會提供的,例如RunbookUrl,核心就是想傳達SOP手冊的重要性。另外,穩定性治理體系裡,警報規則是否預置了RunbookUrl,是很重要的警訊健康度的衡量指標。
一旦有超過幾個部署服務的團隊,跨組織進行故障交流就變得至關重要。在我工作的環境中,成千上萬的工程師會根據自己的判斷將他們所開發的服務部署到生產環境中,每小時可能會有數百次部署。一個看似不相關的服務部署可能會影響另一個服務。在這種情況下,標準化的故障廣播和通訊管道可以發揮很大作用。我曾經遇到過多種罕見的警報訊息 - 意識到其他團隊中的人也看到了類似奇怪現象。透過加入集中式聊天群組來處理故障,我們迅速確定了導致故障的服務並解決了問題。我們做得比任何單獨一人更快地完成了任務。
現在緩解,明天調查。在故障期間,我經常感到“腎上腺素飆升”,想要修復出現問題的地方。通常根本原因是糟糕的程式碼部署,在程式碼變更中存在明顯的錯誤。過去,我會立即跳進去修復錯誤、推送修復並關閉故障,而不是回滾程式碼變更。然而,在故障期間修復根本原因是一個可怕的想法。採用前進式修復收益甚微,損失卻很大。因為新的修復需要迅速完成,所以必須在生產中進行測試。這就是引入第二個錯誤 - 或在現有錯誤之上再出現一個故障 - 的原因。我見過像這樣的故障不斷惡化。只需先集中精力緩解,抵制修復或調查根本原因的衝動。適當的調查可以等到下一個工作天。
譯者註:這一點老司機應該也深有感觸,不要在線上Debug,出現問題立即回滾而不是嘗試發布hotfix版本來修復!
這是在說一個團隊如何處理故障的後續。他們會繼續工作嗎?他們會做小規模的調查嗎?他們是否會在後續工作中花費驚人的精力,停止產品工作以進行系統級修復?
正確進行的事後分析是建立強大系統的基石。好的事後分析既無指責,又十分徹底。 Uber 的事後分析範本隨著工程技術的發展而不斷演變,包括事件概述、影響總覽、時間軸、根本原因分析、經驗教訓以及詳細後續清單等部分。
這是一個類似我在 Uber 工作中使用的複盤模板。
良好的事後分析深入挖掘根本原因並提出改進措施,以更快地預防、檢測或緩解所有類似的故障。當我說深入挖掘時,我的意思是他們不會停留在根本原因上,即錯誤的程式碼變更和程式碼審查者沒有發現錯誤。
他們使用「5why」探索方式進行更深入的挖掘,以達到更有意義的結論。舉個例子:
事件回顧是事後分析的重要配套工具。雖然許多團隊在事後分析方面做得很徹底,但其他團隊可以從額外的意見和對預防性改進的挑戰中受益。同樣重要的是,團隊要有責任感並有權利執行他們提出的系統級改進。
對於認真對待可靠性的組織,最嚴重的故障會由經驗豐富的工程師進行審查和挑戰。組織層級的工程管理人員也應該出席,以提供授權來完成修復——尤其是當這些修復很耗時並阻礙其他工作時。健壯的系統不是一蹴可幾的:它們是透過不斷的迭代建構的。怎麼才能持續迭代?這需要組織層面有持續改善、從故障中學習的文化。
有一些常規活動需要大量投資,但對於保持大型分散式系統的正常運作至關重要。這些是我在優步第一次接觸到的概念——在以前的公司,我們不需要使用這些,因為我們的規模和基礎設施沒有促使我們這樣做。
一個資料中心故障演練是我認為很無聊的事情,直到我觀察了其中幾個實踐。我最初的想法是,設計強大的分散式系統正是為了能夠在資料中心崩潰時保持彈性。如果理論上它可以正常工作,為什麼要經常測試呢?答案與規模有關,並且需要測試服務是否能夠有效地處理新資料中心中突然增加的流量。
我觀察到的最常見的故障場景是在發生故障轉移時,新資料中心的服務沒有足夠的資源來處理全球流量。假設ServiceA和ServiceB分別從兩個資料中心運行。假設資源利用率為60%,每個資料中心都有數十或數百台虛擬機器在運行,並設定警報以在70%時觸發。現在讓我們進行故障轉移,將所有流量從DataCenterA重新導向到DataCenterB。在沒有提供新機器的情況下,DataCenterB突然無法承受負載。提供新機器可能需要足夠長的時間,以至於請求會堆積並開始丟棄。這種阻塞可能會開始影響其他服務,導致其他系統的級聯故障,這些系統甚至不是此故障轉移的一部分。
其他常見的故障場景包括路由等級問題、網路容量問題或背壓痛點。資料中心故障轉移是任何可靠分散式系統應該能夠在沒有任何使用者影響的情況下執行的演習。我強調「應該」——這個演習是測試分散式系統可靠性最有用的練習之一。
譯者註:切流量,本是預案「三板斧」之一。出故障的時候,要確保預案是可用的,那平常就少不了演練。重視起來吧,老鐵們。
計畫的服務停機時間練習是測試整個系統彈性的絕佳方法。這些也是發現特定係統的隱藏依賴項或不適當/意外使用的好方法。雖然對於面向客戶且依賴較少的服務,這種練習相對容易完成,但是對於需要高可用性或被許多其他系統所依賴的關鍵系統來說,則不那麼容易嘍。但是,當某一天這個關鍵系統不可用時會發生什麼?最好透過受控演練來驗證答案,所有團隊都知道並準備好應對意外中斷。
黑盒測試是一種測量系統正確性的方法,盡可能接近最終使用者所看到的條件。這種類型的測試類似於端到端測試,但對於大多數產品來說,擁有適當的黑盒測試需要單獨投入。關鍵使用者流程和最常見的面向使用者的測試場景是好的黑盒可測性範例:以這種方式進行設定可以隨時觸發它們,以檢查系統是否正常運作。
以優步為例,一個明顯的黑盒測試是檢查乘客-司機流程是否在城市層面上正常運作。也就是說,在特定城市內的乘客能否請求優步,並與司機合作並完成行程?一旦這種情況被自動化,這個測試可以定期運行,模擬不同的城市。擁有強大的黑盒測試系統使得驗證系統或部分系統是否正確運作更加容易。它也對故障轉移演練非常有幫助:取得故障轉移回饋最快捷的方法是執行黑盒測試。
上圖是在故障轉移演練失敗時,使用黑盒測試的範例,在演練幾分鐘後手動回滾。
容量規劃對於大型分散式系統同樣重要。所謂大型,是指計算和儲存成本每月達到數萬或數十萬美元。在這個規模下,使用固定數量的部署可能比使用自動擴展的雲端解決方案更便宜。至少,固定部署應該處理「業務常態」流量,並在高峰負載時進行自動擴展。但是,在接下來的一個月內、未來三個月內以及明年需要運行多少最小實例呢?
預測成熟且具有良好歷史資料的系統的未來流量模式並不困難。這對於預算、選擇供應商或鎖定雲端供應商的折扣都很重要。如果您的服務費用很高,而您沒有考慮容量規劃,那麼您就錯過了降低和控製成本的簡單方法。
SLO 代表服務等級目標 - 系統可用性的數字目標。對於每個獨立的服務,定義服務等級 SLO(例如容量、延遲、準確性和可用性的目標)是一種很好的做法。然後,這些 SLO 可以作為警報的觸發器。服務等級SLO 範例可能如下所示:
SLO Metric |
Subcategory |
Value for Service |
##Capacity |
Minumum throughput |
#500 req/sec |
#Maximum expected throughput |
2,500 req/sec |
|
#Latency
|
##預期中值回應時間 | ##50-90ms|
|
||
|
||
##保證正常運行時間 |
以上是Uber實踐:維運大型分散式系統的一些心得的詳細內容。更多資訊請關注PHP中文網其他相關文章!