前言
二十年可以發生很多事情,尤其是當你忙于發展的時候。
二十年前,谷歌有一對小型數據中心,每個中心有幾千臺服務器,通過一對 2.4G 網絡鏈路環形連接。我們使用 Python/ target=_blank class=infotextkey>Python 腳本(如 "Assigner"、"Autoreplacer "和 "Babysitter")運行我們的私有云(雖然當時我們并不這么稱呼它),這些腳本在包含單個服務器名稱的配置文件上運行。我們有一個小型的機器數據庫(MDB),可以幫助整理和保存單個服務器的信息。我們的工程師小團隊使用腳本和配置文件自動解決一些常見問題,并減少了管理服務器小艦隊所需的人工勞動。
時光荏苒,google 的用戶為搜索而來,為免費的 GB GmAIl 而去,我們的機群和網絡也隨之發展壯大。如今,就計算能力而言,我們的規模是 20 年前的 1000 多倍;就網絡而言,我們的規模是 20 年前的 10000 多倍,而且我們在每臺服務器上花費的精力比以前少得多,同時我們的服務堆棧也具有更好的可靠性。我們的工具已經從一系列 Python 腳本發展到集成的服務生態系統,再到默認提供可靠性的統一平臺。我們對分布式系統的問題和故障模式的理解也在不斷發展,因為我們遇到了新的故障類型。我們創建了 不幸之輪 ("Wheel of Misfortune")[1],編寫了 服務最佳實踐指南 ("Service Best Practices guides")[2],出版了《Google's Greatest Hits》,今天,我們非常高興地向大家介紹:
- 本杰明-特雷納-斯洛斯,谷歌 SRE 的創建者
網站可靠性工程二十年的經驗教訓
讓我們從 2016 年說起,那時候 YouTube 還在提供 "阿黛爾的拼車卡拉 OK "和永遠吸引人的 "Pen-PineApple-Apple-Pen"等您最喜愛的視頻。由于 YouTube 的分布式內存緩存系統出現錯誤,YouTube 經歷了長達 15 分鐘的全球中斷,導致 YouTube 服務視頻的能力中斷。以下是我們從這次事件中學到的教訓。
1. 緩解事故的程度應與事故的嚴重程度成正比 (The riskiness of a mitigation should scale with the severity of the outage)
有這樣一個笑話:一個人在網上發布了一張在自己家里看到蜘蛛的照片,The Captain 說:"是時候搬到新房子了!"。這個笑話的意思是,對這一事件(看到一只可怕的蜘蛛)將采取嚴厲的緩解措施(放棄你現在的家,搬到新家)。我們在 SRE 中也有過一些有趣的經歷,那就是選擇一種風險大于其所要解決的故障的緩解措施。在前面提到的 YouTube 故障事件中,一個冒險的負載削減過程并沒有解決故障問題。……反而造成了連鎖故障。
我們深刻地認識到,在事故發生期間,我們應該監控和評估情況的嚴重性,并選擇與嚴重性相適應的故障緩解途徑。在最好的情況下,有風險的緩解措施可以解決故障。而在最壞的情況下,故障緩解措施會失靈,導致中斷時間延長。此外,如果一切正常,您可以做出繞過標準程序的明智決定。
2. 應在緊急情況發生前對恢復機制進行全面測試 (Recovery mechanisms should be fully tested before an emergency)
在高大的城市建筑中進行緊急消防疏散,是第一次使用梯子的絕佳機會。同樣,中斷也是第一次嘗試危險的負載下降過程的絕佳機會。為了在高風險、高壓力的情況下保持冷靜,事先練習恢復機制和緩解措施并驗證以下幾點非常重要:
- 它們能滿足您的需求
- 你知道如何去做
測試恢復機制還有一個有趣的副作用,就是可以降低執行其中某些操作的風險。自從下面這次混亂的故障后,我們加倍努力進行測試。
3. 金絲雀所有變更 (Canary all changes)
有一次,我們想推送緩存配置變更。我們非常確定這不會導致任何不良后果。但 "非常確定" 并不是百分之百的確定。結果發現,緩存對 YouTube 來說是一個相當關鍵的功能,而配置更改帶來了一些意想不到的后果,使服務完全癱瘓了 13 分鐘。如果我們采用漸進式發布策略 金絲雀所有變更 (canaried those global changes)[3],這次故障本可以在對全球造成影響之前得到遏制。在這里閱讀有關金絲雀策略的更多信息[4],以及 在視頻中了解更多信息[5]。
大約在同一時期,YouTube 稍微年輕一些的兄弟公司 Google Calendar 也經歷了一次故障,這也是接下來兩節課的背景。
4. 有一個 "大紅色(急停)按鈕"(Have a "Big Red Button")
"急停按鈕"是一種獨特但非常實用的安全功能:它應該啟動一個簡單、易于觸發的操作,將觸發不良狀態的因素還原為(理想情況下)關閉正在發生的一切。"急停按鈕" 有很多種形狀和大小--在提交潛在的危險操作之前,確定這些紅色按鈕可能是什么非常重要。我們曾險些觸發一次重大故障,還好提交可能觸發變更的工程師在變更傳播之前拔掉了臺式電腦的電源。因此,在計劃重大部署時,請考慮什么是我的 "紅色按鈕"?確保每個服務依賴項都有一個 "紅色按鈕",以便在緊急情況下使用。更多信息,請參閱 "通用緩解措施"[6]!
5. 僅有單元測試是不夠的,還需要集成測試 (Unit tests alone are not enough - integration testing is also needed)
啊。……單元測試。它們驗證單個組件是否能按照我們的要求執行。單元測試有意限制了測試范圍,而且非常有用,但它們也無法完全復制運行時環境和可能存在的生產需求。因此,我們大力提倡集成測試!我們可以使用集成測試來驗證作業和任務是否可以執行冷啟動。事情是否能按我們希望的方式運行?各組件能否按照我們的要求協同工作?這些組件能否成功創建我們想要的系統?我們在一次 Calendar 故障中吸取了這一教訓,在這次故障中,我們的測試并沒有遵循與實際使用相同的路徑,結果導致大量的測試。..... 這并不能幫助我們評估變更在現實中的表現。
轉到 2017 年 2 月發生的一起事件,我們找到了下兩個教訓。
首先,不可用的 OAuth 令牌導致數百萬用戶注銷了設備和服務,32000 臺 OnHub 和 Google wifi 設備執行了出廠重置。由于登錄失敗,手動恢復賬戶的要求增加了 10 倍。谷歌花了大約 12 個小時才完全從故障中恢復過來。
6. 通信渠道!和備份渠道!! 以及這些備份渠道的備份!!!(COMMUNICATION CHANNELS! AND BACKUP CHANNELS!! AND BACKUPS FOR THOSE BACKUP CHANNELS!!!)
是的,那是一段糟糕的時光。你想知道是什么讓情況變得更糟嗎?各團隊都希望能夠使用 Google Hangouts 和 Google Meet 來管理事件。但是,當 3.5 億用戶注銷了他們的設備和服務時。……回過頭來看,依賴這些谷歌服務是一個錯誤的決定。請確保您擁有非依賴性的備份通信渠道,并對其進行過測試。
然后,2017 年的同一事件讓我們更好地理解了 優雅降級 (graceful degradation):[7]
7. 刻意降級性能模式 (Intentionally degrade performance modes)
人們很容易將可用性理解為 "完全正常 "或 "一切正常"...... 但是,通過降級性能模式持續提供最低限度的功能,有助于提供更加一致的用戶體驗。因此,我們謹慎而有意地構建了性能降級模式——因此在不穩定的情況下,用戶可能根本無法看到它(可能現在就在發生!)。服務應優雅地降級,并在特殊情況下繼續運行。
下一課是一項建議,旨在確保您的最后一道防線系統在極端情況下(如自然災害或網絡攻擊)如期運行,從而導致生產力或服務可用性的損失。
8. 測試抗災能力 (Test for Disaster resilience)
除了單元測試和集成測試,還有其他類型的重要測試:災難應急和恢復測試 (disaster resilience and recovery testing)。災難應急 (disaster resilience) 測試驗證您的服務或系統在發生故障、延遲或中斷時能否繼續運行,而恢復測試 (recovery testing) 則驗證您的服務能否在完全關閉后恢復到正常狀態。正如 "經受住意外"[8] 中所述,兩者都應成為業務連續性戰略的關鍵部分。一項有用的活動還可以是讓團隊坐下來,以桌面游戲的方式討論其中一些情景在理論上是如何發生的。這也是一個探索那些可怕的 "如果"的有趣機會,例如,"如果您的部分網絡連接意外關閉怎么辦?
9. 自動化您的緩解措施 (Automate your mitigations)
2023 年 3 月,幾個數據中心的多臺網絡設備幾乎同時發生故障,導致大面積數據包丟失。在這次為期 6 天的故障中,根據網絡故障發生時的位置、服務負載和配置,估計有 70% 的服務受到了不同程度的影響。
在這種情況下,您可以通過自動采取緩解措施來縮短平均解決時間(MTTR)。如果有一個明確的信號表明某個故障正在發生,那么為什么不能自動啟動緩解措施呢?有時,最好先使用自動緩解措施,而將根本原因留待避免對用戶造成影響之后再處理。
10. 縮短兩次發布之間的間隔時間,降低發布出錯的可能性 (Reduce the time between rollouts, to decrease the likelihood of the rollout going wrong)
2022 年 3 月,支付系統發生大面積故障,客戶無法完成交易,導致《口袋妖怪 GO》社區日被推遲。原因是刪除了一個單一的數據庫字段,由于事先已從代碼中刪除了該字段的所有用途,因此本應是安全的。不幸的是,由于系統的一部分發布速度較慢,這意味著實時系統仍在使用該字段。
由于發布之間的延遲時間較長,尤其是在復雜的多組件系統中,因此很難推段發布特定變更的安全性。頻繁發布[9]--在適當測試的情況下--可減少此類故障的意外發生。
11. 單一的全局硬件版本就是單點故障 (A single global hardware version is a single point of failure)
只用一種特定型號的設備來執行關鍵功能可以簡化操作和維護。然而,這意味著如果該型號出現問題,則不再執行該關鍵功能。
這種情況發生在 2020 年 3 月,當時一臺存在未被發現的零日漏洞的網絡設備遇到了觸發該漏洞的流量模式變化。由于整個網絡使用的是同一型號和版本的設備,因此出現了嚴重的區域性故障。幸虧有多條網絡主干線,高優先級流量才得以通過仍可正常工作的替代設備進行傳輸,才避免了全面中斷。
關鍵基礎設施中的潛在漏洞可能潛伏未被發現,直到一個看似無害的事件觸發它們。維護多樣化的基礎設施雖然會產生成本,但卻意味著故障與完全故障之間的差別。
就是這樣!從谷歌二十年的網站可靠性工程中汲取的 11 條經驗。為什么是 11 條經驗?嗯,你看,谷歌網站可靠性部門擁有悠久的歷史,但仍處于鼎盛時期。
>>>>參考資料
- [1] 不幸之輪 ("Wheel of Misfortune")
- https://sre.google/sre-book/accelerating-sre-on-call/
- [2] 服務最佳實踐指南 ("Service Best Practices guides")
- https://sre.google/sre-book/service-best-practices/
- [3] 金絲雀所有變更 (canaried those global changes)
- https://sre.google/workbook/canarying-releases/
- [4] 在這里閱讀有關金絲雀策略的更多信息
- https://storage.googleapis.com/pub-tools-public-publication-data/pdf/24017e52c907294589604a29a86f158828eda078.pdf
- [5] 在視頻中了解更多信息
- https://www.usenix.org/conference/srecon18europe/presentation/davidovic
- [6] "通用緩解措施"
- https://www.oreilly.com/content/generic-mitigations/
- [7] 優雅降級 (graceful degradation)
- [8] "經受住意外"
- https://queue.acm.org/detail.cfm?id=2371516
- [9] 頻繁發布
- https://cloud.google.com/blog/products/devops-sre/using-the-four-keys-to-measure-your-devops-performance
作者丨Adrienne Walcer
編譯丨公眾號:東風微鳴技術博客(ID:EWhisperCN)