- 原文地址:Operating a Large, Distributed System in a Reliable Way: Practices I Learned
- 原文做者:Gergely Orosz
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:Pingren
- 校對者:Ultrasteve,江五渣
在過去的幾年裏,我一直在構建和運維一個大型分佈式系統:Uber 的支付系統。期間我學到了不少分佈式架構概念的知識,並親眼目擊了高負載和高可用的系統不只在構建上,還在運維過程當中充滿挑戰。構建這個系統自己是項有趣的工做。安排系統如何應對 10 倍或 100 倍的流量增加,在任何硬件故障都保證數據的持久化(durable),都對智力有所裨益。然而對我來講,運維一個大型分佈式系統也是一段大開眼界的經歷。html
系統越大,墨菲定律 —— 「凡是可能出錯的事就必定會出錯」 就越可能應驗。這對於被衆多開發人員頻繁部署、涉及多個數據中心、被全球大量用戶使用的系統來講,尤爲如此。過去的幾年裏,我經歷了各類系統故障,其中有不少令我感到驚訝。它們有些是可預測的事情,如硬件故障或非惡意的 bugs 進入生產環境,還有些則是網絡電纜被切斷,或多個級聯故障同時發生。我經歷了許屢次中斷(outages),系統的某些部分沒法正常工做,產生了巨大的業務影響。前端
這篇文章是我在 Uber 工做時,可靠地運維一個大型系統的有效實踐的集合。個人經驗不是獨一無二的 —— 在相似規模的系統上工做的人有着類似的經歷。我和來自 Google,Facebook 和 Netflix 的工程師聊過,他們分享了相似的經驗和解決方案。不管是在本身的數據中心(如 Uber 的大多數狀況)或是在雲端(Uber 有時擴展到),這裏列出的觀點和流程,應該適用於相似規模的系統。可是,對於規模較小或關鍵任務較少的系統而言,這些實踐可能會矯枉過正。android
要知道系統是否健康,咱們須要回答「個人系統是否正常工做?」的問題。爲此,收集系統關鍵部分的數據相當重要。分佈式系統在多臺機器和數據中心上運行多個服務,很難決定什麼纔是真正須要監控的關鍵事項。ios
基礎設施健康監測 若是一個或多個機器/虛擬機過載,分佈式系統的一部分可能降級(degrade)。服務所在的機器的運行情況統計信息 —— 它們的 CPU 利用率、內存使用 —— 是值得監控的基礎信息。有些平臺提供開箱即用的這種監控並能自動擴展實例。在 Uber,咱們有一支優秀的核心基礎設施團隊提供開箱即用的基礎設施監控和警報。不管這如何實現,有必要知道實例或服務的基礎設施何時處在警惕狀態。git
服務健康監控:流量、錯誤、延遲 「這個後端服務是否健康?」是很常見的問題。觀察須要到達端點的流量大小,錯誤率和端點延遲等事項,都爲服務健康情況提供了有價值的信息。我更喜歡使用儀表板觀察這些信息。當構建新的服務時,使用正確的 HTTP 響應映射並監控相應的狀態碼能夠了解系統的狀況。所以,保證客戶端錯誤時返回 4XX 狀態碼映射,服務器錯誤時返回 5XX 狀態碼,這種監控將易於構建且易於理解。github
監控延遲應該多考慮一下。對於生產環境下的服務,目標是爲了大多數最終用戶得到良好的體驗。事實證實,測量平均延遲不是個好的辦法,由於平均值可能會掩蓋一小部分高延遲的請求。測量 p9五、p99 或 p999 —— 即第 9五、99 或 99.9 百分位上的請求延遲 —— 是個更好的指標。這些數據有助於回答諸如「99% 的人請求有多快?」(p99)或「1000 人裏最慢的一個請求有多慢?」(p999)的問題。若是對這個話題感興趣,這篇延遲入門文章挺不錯的,值得一讀。後端
可視化平均值,p95 和 p99 的延遲。請注意,儘管這個端點的平均延遲在 1s 之內,仍是有 1% 的請求須要 2s 或更長的時間才能完成 —— 這就是測量平均值可能掩蓋的信息。服務器
關於監控和可觀察性,還有不少能夠深刻探討的內容。這裏有兩個值得閱讀的資源。一個是 SRE:Google 運維解密裏面關於分佈式系統監控的 4 個黃金指標的部分。他們建議,若是你只能測量四個面向用戶的系統的指標,請關注流量、錯誤、延遲和飽和度。另外一個是來自 Cindy Sridharan 的分佈式系統可觀察性的電子書,這本書也涉及了其它有用的工具,好比事件日誌,指標和請求跟蹤最佳實踐。網絡
業務指標監控 雖然服務健康監控讓咱們瞭解服務是否看上去正常,但它徹底沒法說明是否服務按預期工做,便是否可以「正常經營」。以支付系統爲例,關鍵問題是「用戶是否可使用特定的支付方式來出行?」。識別服務激活的業務事件並監控這些業務事件,是監控最重要的步驟之一。架構
個人團隊全部的服務看上去都在正常運行,然而其中有些服務的關鍵功能卻失效了。在被沒法檢測的中斷打擊以後,咱們創建了業務指標監控。對於咱們的企業和領域來講,這種監控須要量身定製。所以,咱們付出了大量的思考和努力,在 Uber 的可觀察性技術棧上爲咱們本身定製這類的監控。
監控是工程師用於檢查系統當前狀態的一個很好的工具。可是它實際上像一塊墊腳石,只是自動檢測出何時出現了問題並報警,使得工程師能夠採起後續行動。
值班待命(Oncall)自己就是一個普遍的話題 —— Increment 雜誌作了很棒的工做,在它的On-Call 這期雜誌涵蓋了各個方面的內容。我很喜歡將值班待命視爲「你搭建,故你擁有」這一觀念的進一步行動。創建服務的團隊擁有這些服務,也擁有值班待命的責任。對於咱們構建的支付系統服務,個人團隊擁有值班待命的責任。所以不管什麼時候發出警報,值班待命的工程師將會響應並查看詳情。那麼咱們如何將監控轉化爲警報呢?
檢測監控數據中的異常是艱鉅的挑戰,也是機器學習能夠大放異彩的領域。有許多的第三方服務提供了異常檢測。咱們的團隊很幸運,能夠和內部機器學習團隊協做,他們爲 Uber 的用例定製解決方案。紐約的可觀察性團隊寫了一篇有關異常檢測如何在 Uber 工做的有用的文章。從個人團隊角度來看,咱們把監控數據推送到這支團隊的管道(pipeline),並得到各自置信水平的警報。接着咱們決定是否要向工程師報警。
什麼時候發出警報是個有趣的問題。警報太少可能致使錯過有影響的中斷;太多又可能致使不眠之夜,令人心力憔悴。在調整警報系統時,追蹤和分類警報,以及測量信噪比很是重要。標記警報是否可付諸行動,而後採起措施減小非可付諸行動的警報,是實現可持續的 on-call 輪值的很好的一步。
Uber 內部使用的值班待命儀表板示例,由來自維爾紐斯的 Uber 開發者體驗團隊構建。
維爾紐斯的 Uber 開發者工具團隊構建了簡潔的值班待命工具,咱們用它來標記警報,以及讓輪班可視化。咱們的團隊每週都會回顧上次的輪班狀況,分析痛點並花時間提高值班待命的體驗,周而復始。
想象一下:你是這周的值班待命的工程師。一個警報半夜把你叫醒。你調查了是否有生產環境的中斷髮生。呃,彷佛是系統的一部分中止運行了。接下來該怎麼辦?
對於小型系統而言,中斷或許不算什麼大事,由於值班待命的工程師能夠了解發生的問題以及緣由。這些問題一般易於理解和緩解。對於具備多個(微)服務,許多工程師提交代碼到生產環境的複雜系統來講,僅僅是準確地找到潛在問題的位置就頗具挑戰。咱們能夠經過一些標準的流程來改變這種狀況。
運維手冊(Runbooks) 一般附在警報上,描述了簡單的緩解步驟,做爲第一道防線。對於有着良好運維手冊的團隊,值班待命的工程師即便對系統瞭解不深,也不多出現問題。運維手冊須要不斷升級、保持最新版,並在有新的緩解方案時從新修訂。
當有不少支團隊部署服務時,在組織裏溝通中斷的狀況變得很是重要。在個人工做環境,成千上萬的工程師在他們認爲合適的時候在生產環境部署服務,這意味着每小時有上百次的部署發生。服務中的一次看似無關的部署可能會影響到另外一個服務。這種狀況下,標準化的中斷廣播和交流頻道將會有巨大的做用。我屢次遇到從未見過的警報 —— 接着發現其它團隊裏的人也看到了相似的奇怪警報。在一個爲中斷而設的中心聊天羣裏,咱們可以準確地找到致使中斷的服務,並快速地緩解這個問題。相比各自爲戰,咱們做爲一個團體能夠更迅速地完成任務。
馬上緩解,明天調查。當處於中斷過程當中,我一般有種必須修好錯誤的衝動。錯誤的根源一般是一次失敗的代碼部署,代碼修改中有一個明顯的 bug。在過去,我將會直接修好 bug 並推送修復來解決中斷,而不是直接回滾代碼。然而,在一次中斷過程當中解決根本問題是一個糟糕的想法。這幾乎沒有收益,而且一個新修復可能帶來更多的損失。由於這意味着必須快速完成新修復,而且只能在生產環境裏測試。這可能致使第二個 bug 或第二次中斷。我曾見過中斷像這樣失去控制。請專一於緩解最重要的問題,遏制住本身修復或調查根本緣由的衝動。詳細的調查能夠放在下個工做日作。
一支團隊在中斷以後如何應對是很重要的。他們大驚小怪了嗎?他們作了小的調查嗎?他們是否是花了的大量精力進行後續工做,中止產品功能以進行系統級別的修復?
作好過後總結是構建健壯的系統的基石。一個好的過後總結是免責的,也是詳盡的。Uber 的過後總結模版隨着時間進化,它包含了事件摘要、影響概述、事件發展的時間表、根本緣由分析、經驗教訓以及一份詳細的後續行動清單。
一個相似於我在 Uber 使用的過後總結模版
優秀的過後總結深刻研究根本緣由,並提出改善措施,使防止、檢測或緩解全部相似的中斷變得更快。深刻研究根本緣由,並不只停留在代碼審查人員沒能發現代碼修改有 bug 這個層面上。而是使用 5 個爲何的探索技巧來深刻研究,得出一個更有意義的結論。舉個例子:
事故回顧是過後總結的重要協同工具。當許多團隊完成了完全的過後總結,其餘團隊能夠在額外的投入中得到受益,並在預防性的改進上受到挑戰。團隊必須有權執行他們提出的系統級改進,並承擔責任。
對那些嚴肅對待可靠性的組織而言,經驗豐富的工程師會審查和質詢最嚴重的事故。須要組織級別的工程管理來受權修復 —— 特別是當它們很耗時而且阻礙其它工做時。健壯的系統不是一晚上建成的,而是經過持續的迭代建成的。迭代來自不斷地從事故中學習和持續改進的組織文化。
有一些按期活動須要投入大量的時間和精力,但對於保持大型分佈式系統正常運行相當重要。這些是我在 Uber 首次接觸的概念 —— 在過去的公司裏,因爲咱們的規模和基礎設施較小,咱們不須要使用它們。
直到我觀察了一些具體案例,我曾一直認爲數據中心故障轉移演練很乏味。我最初的想法是,設計健壯的分佈式系統,就是指設計可以適應數據中心故障的系統。既然它理論上應該可用,爲何要按期測試?答案與系統的規模和爲了測試服務是否能有效地處理新的數據中心的流量增加有關。
我觀察到最多見的故障狀況是,在發生故障轉移時,服務在新數據中心沒有足夠的資源來應對全局流量。想象一下,服務 A 和服務 B 分別在兩個數據中心運行。咱們假設資源的利用率是 60% —— 每一個數據中心分別運行成百上千個虛擬機 —— 而且警報的觸發點設置在 70%。接着出現一個故障轉移,致使全部的流量從數據中心 A 轉移到了數據中心 B。在沒有配置新機器的狀況下,數據中心 B 沒法應對這樣的負載。配置新機器可能須要較長的時間,而請求可能積壓而且中斷。這種阻塞可能開始影響另外的服務,致使了其餘系統的級聯故障,儘管這些系統並非此次故障轉移的一部分。
數據中心故障轉移中可能的出錯方式
其它常見的故障狀況可能涉及路由級問題,網絡容量問題,或背壓(back pressure)問題。任何可靠的分佈式系統應該可以在不影響用戶的狀況下,執行數據中心故障轉移的演練。我在強調應該 —— 這個演練對於測試分佈式系統網絡可靠性是很是有用的。
計劃內的服務下線演練是測試整個系統彈性的最佳方法。它們對發現特定系統的隱藏的依賴關係或不合適/預期外的使用也頗有幫助。雖然針對面向客戶的和依賴少的服務,這個演練相對容易完成,但對於須要高可用的或依賴多的關鍵系統來講,這樣作並不容易。然而,有一天這個關鍵系統不可用時,將會發生什麼?相比於一次意料以外的中斷,最好仍是經過受控制的演練,在全部團隊都清楚並準備就緒後,驗證這個答案。
黑盒測試是一種在相似最終用戶的條件下,測試系統正確性的方法。這種類型測試很像端到端測試。對於大多數產品而言,須要進行合適的黑盒測試。關鍵用戶流程和最多見的面向用戶的測試情景使「黑盒可被測試」:隨時能夠執行測試來檢查系統是否正常工做。
以 Uber 爲例,一個明顯的黑盒測試是檢查是否乘客-司機流在城市層面上正常工做。即某個特定城市的乘客是否能請求一輛 Uber 出租車,和司機匹配並上路?當這個情景變得自動化,這個測試就能夠按期運行,而且模擬不一樣的城市。擁有健壯的黑盒測試,能夠更容易地驗證系統或系統的部件是否正常工做。它也對故障轉移演練頗有幫助:運行黑盒測試是在故障轉移中得到反饋的最快方式。
在一次失敗的故障轉移演練中使用黑盒測試的例子,手動回滾數分鐘。
容量規劃對於大型分佈式系統一樣很重要。大型的意思是,計算和存儲空間每月將花費幾萬或幾十萬美圓。在這種規模下,具備固定數量的部署可能比使用自擴展的雲端解決方案更便宜。至少,固定部署能夠應對「正常經營」的流量,並在峯值負載下自動擴展。可是,下個月最少應該運行多少實例?接下來的三個月呢?明年呢?
對於成熟且具備良好歷史數據的系統來講,預測將來的流量模式並不困難。並且,這對於預算安排,選擇雲服務商或鎖定雲服務商的折扣都很重要。若是你的服務有着一大筆帳單,而你尚未想過容量規劃,你正錯過一個簡單的減小和控制成本的機會。
SLO 表示了服務質量目標 —— 一個系統可用性的數值目標。對於每一個獨立的服務,定義好服務級的 SLO,好比容量、延遲、準確度、可用度的目標,是一個很好的實踐。這些 SLO 能夠做爲警報的觸發器。一個服務級的 SLO 的例子以下所示:
SLO 指標 | 子類別 | 服務的目標值 |
---|---|---|
容量 | 最小吞吐量 | 500 請求/秒 |
預期最大吞吐量 | 2,500 請求/秒 | |
延遲 | 預期的響應時間中位數 | 50-90ms |
預期的 p99 響應時間 | 500-800ms | |
準確度 | 最大錯誤率 | 0.5% |
可用性 | 保證正常運行 | 99.9% |
業務級的 SLO 或者功能性的 SLO 是在服務之上的抽象。它們將會涵蓋面向用戶或業務的指標。好比,一個業務級的 SLO 能夠像這樣:預計 99.99% 的電子郵件收據,會在行程結束後的一分鐘內發出。這個 SLO 可能能夠映射到服務級的 SLO (例如:支付和電子郵件收據系統的延遲);或者可能須要以別的方式測量。
SLA —— 服務質量協議是服務提供者和服務消費者之間更普遍的協議。一般,多個 SLO 組成了一個 SLA。例如,支付系統保持 99.99% 的可用性能夠是一個 SLA,而它又能夠分解爲每一個支撐系統具體的 SLO。
定義好 SLO 以後,下一步是測量這些目標並報告它們。自動監控和報告 SLA 和 SLO 一般是個複雜的項目,工程團隊和業務團隊會想要下降它的優先級。工程師團隊不會太感興趣,他們已經有了各類級別的監控來實時檢測中斷。而業務團隊寧願優先提供實用的功能,而不是把資源投入一項沒有立竿見影的商業影響的複雜的工程中。
這將引出下個話題:運營大型分佈式系統的組織,早晚須要專門的人員確保系統的可靠性。讓咱們聊聊網站可靠性工程團隊。
網站可靠性工程起源於 Google,從 2003 年左右開始 —— 至今 Google 已經有超過 1500 名 SRE 工程師。隨着生產環境的運維變得愈來愈複雜,須要愈來愈多的自動化,這項工做將變成一種全職工做。這取決於公司什麼時候認識到,工程師在生產自動化中幾乎投入全職工做的時間:這些系統越重要、出現的故障越多,這種改變越早發生。
快速成長的科技公司一般在早期創建一支 SRE 團隊,團隊會制定本身的路線圖。在 Uber,SRE 團隊成立於 2015 年,它的使命是持續管理系統複雜性。其它公司可能在創建專門的基礎設施團隊時組建這樣的團隊。當一家公司發展到,穩定性工做消耗了團隊中很多工程師的時間,就該創建這樣一支專門的團隊了。
SRE 團隊讓全部工程師都更加輕鬆地運維大型分佈式系統。這支 SRE 團隊極可能擁有標準的監控和警報工具。他們極可能購買或搭建值班待命工具,也是求助關於值班待命的最佳實踐的首選。他們能促進事故回顧和系統構建,使檢測、緩解和預防系統中斷變得更加容易。他們確定有助於故障轉移演練,一般主導黑盒測試,並參與容量規劃。他們推進了選擇,改造或建立用於定義和測量 SLO 的標準工具,並報告它們。
鑑於不一樣的公司有不一樣的痛點須要 SRE 解決,SRE 的組織結構在各公司之間是不一樣的。它一般可能也有別的名字:它可能被稱做運維,平臺工程,或是基礎架構。Google 免費發佈了兩本關於網站可靠性的必讀書籍,這是深刻了解 SRE 的最佳讀物。
在構建任何產品時,構建第一個版本僅僅是個開始。在初版以後,將在迭代中添加新功能。若是產品成功並取得了商業上的回報,這些工做會不停地增長。
分佈式系統有着相似的生命週期,然而它們須要更大的投入,不只須要添加新功能,還得跟上規模的擴展。隨着系統承受更高的負載,存儲更多數據,須要更多的工程師爲其工做,系統須要持續的維護才能保持平穩地運行。許多人第一次構建分佈式系統時,把這個系統看成了一輛車:一旦造好,只須要每隔幾個月進行必要的維護。這樣類比其實不太對。
我喜歡把運維分佈式系統看做運營一家大型機構,好比一家醫院。爲了確保醫院運營良好,須要持續的驗證和檢查(監控、警報、黑盒測試)。新員工和設備(新工程師和新服務)都須要受到訓練。隨着工程師和服務的數量的增加,舊的方式變得低效:就像農村小診所與城市大醫院有着不一樣的運營方式。改進效率成了一項全職工做,測量和報告效率變得重要。就像大醫院有更多的支持人員,好比財務、人資或安保;運維大型的分佈式系統一樣依賴於支持團隊,好比基礎設施和 SRE 團隊。
爲了使分佈式系統可靠,組織機構須要持續在系統運維和系統的基礎平臺上進行更大的投入。
雖然這篇文章內容很長,但它仍僅僅略窺門徑。若是要深刻探索分佈式系統的運維,我推薦的資源以下:
書籍:
在線資源:
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。