讓系統崩潰的黑天鵝分類
黑天鵝 用來比喻造成嚴重影響的小概率事件(比如 2008 年的金融危機)。在生產環境的系統中,黑天鵝是指這樣的事情:它引發了你不知道的問題,造成了重大影響,不能快速修復或回滾,也不能用值班說明書上的其他標準響應來解決。它是事發幾年後你還在給新人說起的事件。
從定義上看,黑天鵝是不可預測的,不過有時候我們能找到其中的一些模式,針對有關聯的某一類問題準備防禦措施。
例如,大部分故障的直接原因是變更(代碼、環境或配置)。雖然這種方式觸發的 bug 是獨特的、不可預測的,但是常見的金絲雀發布對避免這類問題有一定的作用,而且自動回滾已經成了一種標準止損策略。
隨著我們的專業性不斷成熟,一些其他的問題也正逐漸變得容易理解,被歸類到某種風險並有普適的預防策略。
公布出來的黑天鵝事件
所有科技公司都有生產環境的故障,只不過並不是所有公司都會分享他們的事故分析。那些公開討論事故的公司幫了我們的忙。下列事故都描述了某一類問題,但它們絕對不是只一個孤例。我們的系統中都有黑天鵝在潛伏著,只是有些人還不知道而已。
達到上限
達到任何類型的限制都會引發嚴重事故。這類問題的一個典型例子是 2017 年 2 月 Instapaper 的一次服務中斷。我把這份事故報告給任何一個運維工作者看,他們讀完都會脊背發涼。Instapaper 生產環境的資料庫所在的文件系統有 2 TB 的大小限制,但是資料庫服務團隊並不知情。在沒有任何報錯的情況下,資料庫不再接受任何寫入了。完全恢復需要好幾天,而且還得遷移資料庫。
資源限制有各式各樣的觸發場景。Sentry 遇到了 Postgres 的最大事務 ID 限制。Platform.sh 遇到了管道緩衝區大小限制。SparkPost 觸發了 AWS 的 DDoS 保護。Foursquare 在他們的一個 MongoDB 耗盡內存時遭遇了性能驟降。
提前了解系統限制的一個辦法是定期做測試。好的壓力測試(在生產環境的副本上做)應該包含寫入事務,並且應該把每一種數據存儲都寫到超過當前生產環境的容量。壓力測試時很容易忽略的是次要存儲(比如 Zookeeper)。如果你是在測試時遇到了資源限制,那麼你還有時間去解決問題。鑒於這種資源限制問題的解決方案可能涉及重大的變更(比如數據存儲拆分),所以時間是非常寶貴的。
說到雲產品的使用,如果你的服務產生了異常的負載,或者你用的產品或功能還沒有被廣泛使用(比如老舊的或者新興的),那麼你遇到資源上限的風險很大。對這些雲產品做一下壓力測試是值得的。不過,做之前要提醒一下你的雲服務提供商。
最後,知道了哪裡有限制之後,要增加監控(和對應文檔),這樣你才能知道系統在什麼時候接近了資源上限。不要寄希望於那些還在維護服務的人會記得。
擴散的慢請求
「這個世界的關聯性遠比我們想像中更大。所以我們看到了更多 Nassim Taleb 所說的『黑天鵝事件』 —— 即罕見事件以更高的頻率離譜地發生了,因為世界是相互關聯的」 —— Richard Thaler
HostedGraphite 的負載均衡器並沒有託管在 AWS 上,卻被 AWS 的服務中斷給搞垮了,他們關於這次事故原因的分析報告很好地詮釋了分散式計算系統之間存在多麼大的關聯。在這個事件里,負載均衡器的連接池被來自 AWS 上的客戶訪問佔滿了,因為這些連接很耗時。同樣的現象還會發生在應用的線程、鎖、資料庫連接上 —— 任何能被慢操作佔滿的資源。
這個 HostedGraphite 的例子中,慢速連接是外部系統施加的,不過慢速連接經常是由內部某個系統的飽和所引起的,飽和與慢操作的級聯,拖慢了系統中的其他部分。Spotify 的一個事故就說明了這樣的傳播 —— 流媒體服務的前端被另一個微服務的飽和所影響,造成健康檢查失敗。強制給所有請求設置超時時間,以及限制請求隊列的長度,可以預防這一類故障傳播。這樣即使有問題,至少你的服務還能承擔一些流量,而且因為整體上你的系統里故障的部分更少了,恢復起來也會更快。
重試的間隔應該用指數退避來限制一下,並加入一些時間抖動。Square 有一次服務中斷是 Redis 存儲的過載,原因是有一段代碼對失敗的事務重試了 500 次,沒有任何重試退避的方案,也說明了過度重試的潛在風險。另外,針對這種情況,斷路器設計模式也是有用的。
應該設計出監控儀錶盤來清晰地展示所有資源的使用率、飽和度和報錯,這樣才能快速發現問題。
突發的高負載
系統在異常高的負載下經常會發生故障。用戶天然會引發高負載,不過也常常是由系統引發的。午夜突發的 cron 定時任務是老生常談了。如果程序讓移動客戶端同時去獲取更新,這些客戶端也會造成突發的大流量(當然,給這種請求加入時間抖動會好很多)。
在預定時刻同時發生的事件並不是突發大流量的唯一原因。Slack 經歷過一次短時間內的多次服務中斷,原因是非常多的客戶端斷開連接後立即重連,造成了突發的大負載。 CircleCI 也經歷過一次嚴重的服務中斷,當時 Gitlab 從故障中恢復了,所以資料庫里積累了大量的構建任務隊列,服務變得飽和而且緩慢。
幾乎所有的服務都會受突發的高負載所影響。所以對這類可能出現的事情做應急預案 —— 並測試一下預案能否正常工作 —— 是必須的。客戶端退避和減載通常是這些方案的核心。
如果你的系統必須不間斷地接收數據,並且數據不能被丟掉,關鍵是用可伸縮的方式把數據緩衝到隊列中,後續再處理。
自動化系統是複雜的系統
「複雜的系統本身就是有風險的系統」
—— Richard Cook, MD
過去幾年裡軟體的運維操作趨勢是更加自動化。任何可能降低系統容量的自動化操作(比如擦除磁碟、退役設備、關閉服務)都應該謹慎操作。這類自動化操作的故障(由於系統有 bug 或者有不正確的調用)能很快地搞垮你的系統,而且可能很難恢復。
谷歌的 Christina Schulman 和 Etienne Perot 在用安全規約協助保護你的數據中心的演講中給了一些例子。其中一次事故是將谷歌整個內部的內容分發網路(CDN)提交給了擦除磁碟的自動化系統。
Schulman 和 Perot 建議使用一個中心服務來管理規約,限制破壞性自動化操作的速度,並能感知到系統狀態(比如避免在最近有告警的服務上執行破壞性的操作)。
自動化系統在與運維人員(或其他自動化系統)交互時,也可能造成嚴重事故。Reddit 遭遇過一次嚴重的服務中斷,當時他們的自動化系統重啟了一個服務,但是這個服務是運維人員停掉做維護的。一旦有了多個自動化系統,它們之間潛在的交互就變得異常複雜和不可預測。
所有的自動化系統都把日誌輸出到一個容易搜索的中心存儲上,能幫助到對這類不可避免的意外情況的處理。自動化系統總是應該具備這樣一種機制,即允許快速地關掉它們(完全關掉或者只關掉其中一部分操作或一部分目標)。
防止黑天鵝事件
可能在等著擊垮系統的黑天鵝可不止上面這些。有很多其他的嚴重問題是能通過一些技術來避免的,像金絲雀發布、壓力測試、混沌工程、災難測試和模糊測試 —— 當然還有冗餘性和彈性的設計。但是即使用了這些技術,有時候你的系統還是會有故障。
為了確保你的組織能有效地響應,在服務中斷期間,請保證關鍵技術人員和領導層有辦法溝通協調。例如,有一種你可能需要處理的煩人的事情,那就是網路完全中斷。擁有故障時仍然可用的通信通道非常重要,這個通信通道要完全獨立於你們自己的基礎設施及對其的依賴。舉個例子,假如你使用 AWS,那麼把故障時可用的通信服務部署在 AWS 上就不明智了。在和你的主系統無關的地方,運行電話網橋或 IRC 伺服器是比較好的方案。確保每個人都知道這個通信平台,並練習使用它。
另一個原則是,確保監控和運維工具對生產環境系統的依賴儘可能的少。將控制平面和數據平面分開,你才能在系統不健康的時候做變更。不要讓數據處理和配置變更或監控使用同一個消息隊列,比如,應該使用不同的消息隊列實例。在 SparkPost: DNS 掛掉的那一天 這個演講中,Jeremy Blosser 講了一個這類例子,很關鍵的工具依賴了生產環境的 DNS 配置,但是生產環境的 DNS 出了問題。
對抗黑天鵝的心理學
處理生產環境的重大事故時會產生很大的壓力。為這些場景制定結構化的事故管理流程確實是有幫助的。很多科技公司(包括谷歌)成功地使用了聯邦應急管理局事故指揮系統的某個版本。對於每一個值班的人,遇到了他們無法獨立解決的重大問題時,都應該有一個明確的尋求協助的方法。
對於那些持續很長時間的事故,有一點很重要,要確保工程師不會連續工作到不合理的時長,確保他們不會不吃不睡(沒有報警打擾的睡覺)。疲憊不堪的工程師很容易犯錯或者漏掉了可能更快解決故障的信息。
了解更多
關於黑天鵝(或者以前的黑天鵝)事件以及應對策略,還有很多其他的事情可以說。如果你想了解更多,我強烈推薦你去看這兩本書,它們是關於生產環境中的彈性和穩定性的:Susan Fowler 寫的《生產微服務》,還有 Michael T. Nygard 的 《Release It!》。
via: https://opensource.com/article/18/10/taxonomy-black-swans
作者:Laura Nolan 選題:lujun9972 譯者:BeliteX 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive