Uber實踐:運維大型分布式系統的一些心得

本文是 Uber 的工程師 Gergely Orosz 的文章,原文地址在:https://blog.pragmaticengineer.com/operating-a-high-scale-distributed-system/

在過去的幾年里,我一直在構建和運營一個大型分布式系統:優步的支付系統。在此期間,我學到了很多關于分布式架構概念的知識,并親眼目睹了高負載和高可用性系統運行的挑戰(一個系統遠遠不是開發完了就完了,線上運行的挑戰實際更大)。構建系統本身是一項有趣的工作。規劃系統如何處理10x / 100x流量的增加,確保數據持久,面對硬件故障處理等等,這些都需要智慧。不管怎樣,運維大型分布式系統對我來說是一次令人大開眼界的體驗。

系統越大,墨菲的“什么可能出錯,就會出錯”的定律就越會體現。頻繁部署、部署代碼的開發人員數量很多,涉及多個數據中心、系統被大量全球用戶使用,這種出錯概率越大。在過去的幾年里,我經歷過各種各樣的系統故障,其中很多讓我感到驚訝。有些來自可預測的事情,比如硬件故障或一些看起來無害的Bug,還有數據中心線纜被挖斷、同時發生多個級聯故障。我經歷了數十次業務停擺,系統的某些部分無法正常工作,從而導致巨大的業務影響。

這篇文章是我在Uber工作時總結的,可以有效運維大型系統的實踐的集合。我的經驗并不是獨一無二的 – 在類似規模的系統上工作的人也經歷了類似的旅程。我與Google,Facebook和Netflix的工程師進行了交談,他們分享了類似的經驗和解決方案。這里列出的許多想法和流程應該適用于類似規模的系統,無論是在自己的數據中心(如Uber大多數情況下)上運行,還是在云上運行(Uber 有時會把部分服務彈性部署到云上)。但是,對于規模較小或較少關鍵任務的系統而言,這些做法可能過于苛刻。

涉及的內容很多——我將討論以下主題:

  • 監控
  • 值班,異常檢測和警報
  • 故障和事件管理流程
  • 事后分析,事件回顧和持續改進文化
  • 故障演習,容量規劃和黑盒測試
  • SLOs、SLAs 及其報告
  • SRE 作為獨立團隊
  • 可靠性作為持續投入
  • 更多推薦閱讀

監控

要知道系統是否健康,我們需要回答“我的系統是否正常工作”的問題?為此,收集系統關鍵部分的數據至關重要。對于在多臺計算機和數據中心上運行多個服務的分布式系統,可能很難確定要監控的關鍵內容是什么。

基礎設施健康監測?如果一個或多個計算機/虛擬機過載,則分布式系統的某些部分可能會降級。機器的健康狀況,CPU利用率、內存使用情況,是值得監控的基礎內容。有些平臺可以開箱即用地處理這種監控和自動擴展實例。在優步,我們擁有一支優秀的核心基礎設施團隊,提供開箱即用的基礎設施監控和警報。不管技術層面如何實現,實例或基礎設施出問題的時候,監控平臺需要提供必要的信息。

服務運行狀況監控:流量,錯誤,延遲。我們經常需要回答“這個后端服務是否健康?”這樣的問題。觀察訪問端點的請求流量、錯誤率和端點延遲等事項都可以提供有關服務健康狀況的有價值信息。我更喜歡將這些都顯示在儀表板上。在構建新服務時,通過使用正確的HTTP響應映射并監視相關代碼可以對系統有很多了解。因此,確保客戶端錯誤能返回4XX,以及如果服務器錯誤則返回5xx,這種監控易于構建且易于解釋。

監測延遲值得再考慮一下。對于生產服務,目標是讓大多數最終用戶獲得良好的體驗。事實證明,測量平均延遲并不是一個很好的指標,因為這個平均值可以隱藏一小部分高延遲請求。測量p95,p99或p999 – 第95百分位,第99百分位或第99.9百分位的請求所經歷的延遲 – 是一個更好的指標。這些數字有助于回答諸如“99%的人的請求有多快?”之類的問題(p99)。或“1000人中,至少有一人經歷了多慢的延遲?” (p999)。對于那些對這個主題更感興趣的人,這篇延遲入門文章可以進一步閱讀。

Uber實踐:運維大型分布式系統的一些心得

從圖上可以明顯看出,平均延遲、p95、p99 差異還是比較大的。所以平均延遲有可能掩蓋一些問題。

圍繞監控和可觀察性有很多更有深度的內容。值得一讀的兩個資源是Google的SRE書和關于分布式系統監控的四個黃金指標的部分。他們建議,如果您只能測量面向用戶的系統的四個指標,請關注流量,錯誤,延遲和飽和度。比較簡短的材料的話,推薦來自Cindy Sridharan的分布式系統可觀察性電子書,它涉及其他有用的工具,如事件日志,指標和跟蹤最佳實踐。

業務指標監控。監控服務模塊,可以告訴我們服務模塊運行的如何如何正常,但無法告知我們業務是否按預期工作,是否“照常營業”。在支付系統,一個關鍵問題是,“人們可以使用特定的支付方式進行支付業務嗎?”。識別業務事件并對其監控,是最重要的監控步驟之一。

雖然我們建立了各種監控,有些業務問題仍然無法探測到,這讓我們遭受了巨大的痛苦,最終建立了業務指標的監控。有時我們所有的服務看起來都在正常運行,但關鍵產品功能不可用!這種監控對我們的組織和領域來說非常有用。因此,我們必須在Uber的可觀察性技術堆棧的基礎上,為自己定制這種類型的監控做了大量的思考和努力。

譯者注:業務指標監控這一點,我們實在是太深有同感了,之前在滴滴有時就是發現所有服務都正常,但是業務不好使。我們現在創業做的北極星系統,就是專門應對這個問題的。感興趣的朋友可以在公眾號后臺給我留言,或加我好友 picobyte 交流試用。

Oncall,異常檢測和警報

監控對于洞察系統的當前狀態而言,是一個很棒的工具。但這只是自動檢測問題并發出警報以供人們采取行動的一個墊腳石。

Oncall 本身是一個廣泛的話題 – Increment 雜志在其 “On-Call 問題”中涵蓋了許多方面的內容。我的強烈認為,如果你擁有了”you build it, you own it”的心態,那隨著而來的就是 OnCall。構建服務的團隊擁有這些服務,也負責值班。我們的團隊負責支付服務的值班。因此,每當出現警報時,值班工程師都會響應并查看詳細信息。但是如何從監控到警報呢?

從監控數據中檢測異常是一個艱巨的挑戰,也是機器學習可以發光的領域。有很多第三方服務提供異常檢測。再次幸運的是,我們團隊有一個內部機器學習團隊與之合作,他們根據Uber的使用情況量身定制了解決方案。位于紐約的 Observability 團隊撰寫了一篇有用的文章,介紹?Uber 的異常檢測工作原理。從我的團隊的角度來看,我們將監控數據推送到該團隊的管道,并獲得具有各自置信度的警報。然后我們決定是否應該呼叫工程師。

何時觸發警報是一個有趣的問題。警報太少可能意味著錯過有影響的中斷。太多會導致不眠之夜并使人筋疲力盡。跟蹤和分類警報以及測量信噪比對于調整警報系統至關重要。檢查警報并標記它們是否可操作,然后采取措施減少不可操作的警報,這是朝著實現可持續的隨叫隨到輪換邁出的良好一步。

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實踐:運維大型分布式系統的一些心得

這是一個類似我在 Uber 工作中用到的復盤模板。

良好的事后分析深入挖掘根本原因并提出改進措施,以更快地預防、檢測或緩解所有類似的故障。當我說深入挖掘時,我的意思是他們不會停留在根本原因上,即錯誤的代碼更改和代碼審查者沒有發現錯誤。

他們使用“5why”探索方式進行更深入的挖掘,以達到更有意義的結論。舉個例子:

  • 為什么會出現這個問題?–> 因為代碼里引入了bug。
  • 為什么其他人沒有發現這個錯誤?–> 代碼審查員沒有注意到代碼更改可能會導致此類問題。
  • 我們為什么只依賴于代碼審查員捕獲此錯誤?–> 因為我們沒有針對此用例的自動化測試。
  • “為什么我們沒有針對此用例的自動化測試?” –> 因為在沒有測試帳戶的情況下很難進行測試。
  • 我們為什么沒有測試帳戶? –> 因為該系統尚不支持它們
  • 結論:這個問題指向了缺乏測試賬戶的系統性問題。建議將測試賬戶支持添加到系統中。接下來,編寫所有未來類似代碼更改的自動化測試。

事件回顧是事后分析的重要配套工具。雖然許多團隊在事后分析方面做得很徹底,但其他團隊可以從額外的輸入和對預防性改進的挑戰中受益。同樣重要的是,團隊要有責任感并有權執行他們提出的系統級改進。

對于認真對待可靠性的組織,最嚴重的故障會由經驗豐富的工程師進行審查和挑戰。組織級別的工程管理人員也應該出席,以提供授權來完成修復——尤其是當這些修復很耗時并阻礙其他工作時。健壯的系統不是一蹴而就的:它們是通過不斷的迭代構建的。怎么才能持續迭代?這需要組織層面有持續改進、從故障中學習的文化。

故障演習,容量規劃和黑盒測試

有一些常規活動需要大量投資,但對于保持大型分布式系統的正常運行至關重要。這些是我在優步第一次接觸到的概念——在以前的公司,我們不需要使用這些,因為我們的規模和基礎設施沒有促使我們這樣做。

一個數據中心故障演練是我認為很無聊的事情,直到我觀察了其中幾個實踐。我最初的想法是,設計強大的分布式系統正是為了能夠在數據中心崩潰時保持彈性。如果理論上它可以正常工作,為什么要經常測試呢?答案與規模有關,并且需要測試服務是否能夠有效地處理新數據中心中突然增加的流量。

我觀察到的最常見的故障場景是在發生故障轉移時,新數據中心的服務沒有足夠的資源來處理全球流量。假設ServiceA和ServiceB分別從兩個數據中心運行。假設資源利用率為60%,每個數據中心都有數十或數百臺虛擬機在運行,并設置警報以在70%時觸發。現在讓我們進行故障轉移,將所有流量從DataCenterA重定向到DataCenterB。 在沒有提供新機器的情況下,DataCenterB突然無法承受負載。提供新機器可能需要足夠長的時間,以至于請求會堆積并開始丟棄。這種阻塞可能會開始影響其他服務,導致其他系統的級聯故障,這些系統甚至不是此故障轉移的一部分。

Uber實踐:運維大型分布式系統的一些心得

其他常見的故障場景包括路由級別問題、網絡容量問題或背壓痛點。數據中心故障轉移是任何可靠分布式系統應該能夠在沒有任何用戶影響的情況下執行的演習。我強調“應該”——這個演習是測試分布式系統可靠性最有用的練習之一。

譯者注:切流量,本就是預案“三板斧”之一。出故障的時候,要保證預案是可用的,那平時就少不了演練。重視起來吧,老鐵們。

計劃的服務停機時間練習是測試整個系統彈性的極好方法。這些也是發現特定系統的隱藏依賴項或不適當/意外使用的好方法。雖然對于面向客戶且依賴較少的服務,這種練習相對容易完成,但是對于需要高可用性或被許多其他系統所依賴的關鍵系統來說,則不那么容易嘍。但是,當某一天這個關鍵系統不可用時會發生什么?最好通過受控演練來驗證答案,所有團隊都知道并準備好應對意外中斷。

黑盒測試是一種測量系統正確性的方法,盡可能接近最終用戶所看到的條件。這種類型的測試類似于端到端測試,但對于大多數產品來說,擁有適當的黑盒測試需要單獨投入。關鍵用戶流程和最常見的面向用戶的測試場景是好的黑盒可測性示例:以這種方式進行設置可以隨時觸發它們,以檢查系統是否正常工作。

以優步為例,一個明顯的黑盒測試是檢查乘客-司機流程是否在城市層面上正常工作。也就是說,在特定城市內的乘客能否請求優步,并與司機合作并完成行程?一旦這種情況被自動化,這個測試可以定期運行,模擬不同的城市。擁有強大的黑盒測試系統使得驗證系統或部分系統是否正確工作更加容易。它還對故障轉移演練非常有幫助:獲取故障轉移反饋最快捷的方法是運行黑盒測試。

Uber實踐:運維大型分布式系統的一些心得

上圖是在故障轉移演練失敗時,使用黑盒測試的示例,在演練幾分鐘后手動回滾。

容量規劃對于大型分布式系統同樣重要。所謂大型,是指計算和存儲成本每月達到數萬或數十萬美元。在這個規模下,使用固定數量的部署可能比使用自動擴展的云解決方案更便宜。至少,固定部署應該處理“業務常態”流量,并在高峰負載時進行自動擴展。但是,在接下來的一個月內、未來三個月內以及明年需要運行多少最小實例呢?

預測成熟且具有良好歷史數據的系統的未來流量模式并不困難。這對于預算、選擇供應商或鎖定云提供商的折扣都很重要。如果您的服務費用很高,而您沒有考慮容量規劃,那么您就錯過了降低和控制成本的簡單方法。

SLOs, SLAs 以及相關報告

SLO 代表服務級別目標 – 系統可用性的數字目標。對于每個獨立的服務,定義服務級別 SLO(例如容量、延遲、準確性和可用性的目標)是一種很好的做法。然后,這些 SLO 可以作為警報的觸發器。服務級別 SLO 示例可能如下所示:

SLO Metric

Subcategory

Value for Service

Capacity

Minumum throughput

500 req/sec

Maximum expected throughput

2,500 req/sec

Latency

Expected median response time

50-90ms

Expected p99 response time

500-800ms

Accuracy

Maximum error rate

0.5%

Availability

Guaranteed uptime

99.9%

業務級 SLO 或功能 SLO 是服務之上的抽象。它們將涵蓋用戶或面向業務的指標。例如,業務級 SLO 可能是這樣的:期望 99.99% 的電子郵件收據在旅行完成后的 1 分鐘內發送。此 SLO 可能映射到服務級別 SLO(例如支付和電子郵件接收系統的延遲),或者它們可能需要以不同方式衡量。

SLA – 服務水平協議 – 是服務提供者和服務消費者之間更廣泛的協議。通常,多個 SLO 組成一個 SLA。例如,99.99% 可用的支付系統可以是 SLA,它分解為每個支持系統的特定 SLO。

定義 SLO 后,下一步是衡量這些并報告它們。對 SLA 和 SLO 進行自動化監控和報告通常是一項復雜的項目,工程團隊和業務部門都傾向于降低其優先級。工程團隊可能不太感興趣,因為他們已經有各種級別的監控來實時檢測故障。另一方面,業務部門更愿意將重點放在提供功能上,而不是投資于一個沒有立即商業影響的復雜項目中。

這就引出了下一個話題:運營大型分布式系統的組織遲早需要為這些系統的可靠性投入專門的人員。讓我們來談談網站可靠性工程團隊。

SRE 作為獨立團隊

網站可靠性工程(Site Reliability Engineering)起源于谷歌,大約在2003年左右開始,現在已經發展成為擁有超過1,500名SRE工程師的團隊。隨著生產環境運營變得越來越復雜,并需要更多自動化操作,這項工作很快就會成為一項全職工作。公司意識到他們有工程師正在全職從事生產自動化的時間因情況而異:這些系統越關鍵、故障越多,則此類情況出現得越早。

快速發展的科技公司通常會在早期組建 SRE 團隊,由他們制定自己的路線圖。在優步,SRE 團隊成立于 2015 年,其使命是隨著時間的推移管理系統復雜性。其他公司可能會在創建專門的基礎架構團隊時同時啟動這樣的團隊。當一家公司發展到跨團隊的可靠性工作占用了很多工程師的時間時,是時候為此設立一個專門的團隊了。

有了 SRE 團隊,這個團隊可以讓所有工程師更輕松地維護大型分布式系統的操作方面。SRE 團隊可能擁有標準的監控和警報工具。他們可能購買或構建 oncall 工具,并且是 oncall 最佳實踐的 goto 團隊。他們可能會促進故障復盤并構建系統,以更輕松地檢測、緩解和防止故障。他們當然有助于故障轉移演練,經常推動黑盒測試,并參與容量規劃。他們推動選擇、定制或構建標準工具來定義和衡量 SLO 并報告它們。

鑒于公司有不同的痛點,他們尋求 SRE 來解決,因此 SRE 組織在公司之間是不同的。這個團隊的名稱通常也會不同:可能被稱為運維、平臺工程或基礎設施。Google 出版了兩本關于站點可靠性的必讀書籍,這些書籍可免費獲取,是深入了解 SRE 的絕佳讀物。

可靠性作為持續投入

在構建任何產品時,構建第一個版本只是一個開始。在 v1 之后,新功能會添加到即將到來的迭代中。如果產品成功并帶來業務成果,那么工作就會繼續進行。

分布式系統具有相似的生命周期,只是它們需要更多投資,不僅僅是為了新功能,還要跟上擴展的步伐。隨著系統開始承受更多負載、存儲更多數據、更多工程師對其進行處理,它需要持續關注以保持平穩運行。很多人第一次構建分布式系統時會認為這個系統就像一輛汽車:一旦建好,只需要每幾個月進行必要的維護。但是這種比較與實際情況相去甚遠。

我喜歡把操作分布式系統的努力比作經營大型組織,例如醫院。為了確保醫院運轉良好,需要進行持續的驗證和檢查(監控、警報、黑盒測試)。不斷有新員工和設備加入:對于醫院來說,這是像護士和醫生這樣的員工以及新的醫療設備;對于分布式系統來說,則是招募新工程師和添加新服務。隨著人數和服務數量的增長,舊有做事方式變得低效:就像鄉村小診所與大都市中的大型醫院不同一樣。提出更有效率的方法成為全職工作,并且測量并報告效率變得重要。就像大型醫院有財務、人力資源或安全等支持性質的辦公室人員一樣,經營較大規模分布式系統也依賴基礎架構和SRE等支持團隊。

為了讓團隊運行可靠的分布式系統,組織需要持續投資于這些系統的操作以及它們所構建的平臺。

? 版權聲明
THE END
喜歡就支持一下吧
點贊13 分享