在冬季2012年,Netflix公司遭受了 長時間斷電 持續了七個小時,由於在美東地區的AWS彈性負載均衡服務的問題。(Netflix的運行在Amazon Web Services的[AWS] -我們沒有自己的任何數據中心,所有與Netflix的互動是從AWS服務,除了視頻的實際流。一旦你點擊“播放”時,實際的視頻文件是從我們自己的CDN服務。)在停電,沒有流量進入美東是達到了我們的服務。
為了防止這種情況再次發生,我們決定建立地區性故障切換的系統,該系統是有彈性的,以我們的基礎服務提供商的故障。故障轉移是保護計算機系統從故障時主系統出現故障時,其中備用設備自動接管的方法。
區域故障轉移降低了風險
我們擴展到三個AWS區域:兩個在美國(美國東部和美國西部),一個在歐盟(EU)。我們保留了足夠的容量來執行故障轉移,以便我們可以吸收單個區域的中斷。
典型的故障轉移如下所示:
- 1.意識到其中一個地區遇到了麻煩。
- 2.擴大兩個救世主地區。
- 3.代理從陷入困境的區域到救世主的一些流量。
- 4.將DNS從問題區域更改為救世區域。
接下來讓我們探索每一步。
1.找出問題
我們需要指標,最好是一個指標,它可以告訴我們系統的健康狀況。在Netflix,我們使用稱為每秒流啟動的業務指標(簡稱SPS)。這是已成功開始播放節目的客戶端數量。
我們按區域劃分了這些數據,並且在任何給定時間我們都可以繪製每個區域的SPS數據,並將其與前一天和前一週的SPS值進行比較。當我們注意到SPS圖表下降時,我們知道我們的客戶無法啟動流媒體節目,因此我們遇到了麻煩。
此問題不一定是雲基礎設施的問題。這可能是組成 Netflix 生態系統的數百個微服務中的一個糟糕代碼的部署,例如海底電纜的切割等。我們可能不知道其原因;我們只知道某處出了問題。
如果僅在一個區域中觀察到 SPS 中的這種下降,則它是區域性故障轉移的理想選擇。如果在多個區域觀察到下降,很不幸,因為我們只有足夠的能力一次疏解一個區域。這正是我們將微服務一次部署到一個區域的原因。如果部署出現問題,我們可以立即撤銷並稍後調試此問題。同樣,我們希望避免故障轉移出現在流量重定向之後(如在 DDoS 攻擊中發生的那樣)。
2.擴大救世主
一旦我們確定了病區,我們就應該準備其他區域(“救世主”)來接收來自病區的交通。在我們打開消防水帶之前,我們需要適當地縮放救生區域中的堆疊。
在這種情況下,縮放的適當含義是什麼?Netflix的流量模式全天都不是靜態的。我們有高峰觀看時間,通常是在下午6點到9點之間。但是在世界不同地區的不同時間都有6次拍攝。美國東部的交通高峰時段比美國西部高3小時,比歐盟地區落後8小時。
當我們在美國東部進行故障轉移時,我們會將來自美國東部的流量發送到歐盟,並將流量從南美洲發送到美國西部。這是為了降低延遲併為我們的客戶提供最佳體驗。
考慮到這一點,我們可以使用線性迴歸來預測將使用每個微服務的歷史擴展行為路由到一天中的特定時間(以及每週的一天)的救急區域的流量。
一旦我們確定了每個微服務的適當大小,我們通過設置每個集群的所需大小來觸發每個微服務的擴展,然後讓 AWS 發揮其魔力。
3. 代理流量
既然微服務集群已經擴展,我們開始代理從故障區域到救急區域的流量。Netflix 已經構建了一個名為 Zuul 的高性能、跨區域邊緣代理,並已經對其開源。
這些代理服務旨在驗證請求、執行減載、重試已失敗請求等。Zuul 代理也可以執行跨區域代理。我們使用此功能將一小撮流量路由到遠離故障區域,然後逐漸增加已重新路由的流量,直到達到 100%。
這種漸進式代理允許我們的服務使用其擴展策略來執行任意用於處理接入流量所需的響應式擴展。這是為了補償我們在進行擴展預測所耗費的時間與擴展每個集群所耗費時間之間的流量變化。
Zuul 在這一點上完成了繁重的工作,它將所有來自故障區域的流量路由到正常區域。但現在是完全廢棄受影響區域的時候了。此處是 DNS 切換髮揮作用的地方。
4. 切換 DNS
故障轉移的最後一步是更新指向受影響區域的 DNS 記錄,並將它們重定向到正常區域。這將完全把所有客戶流量移出故障區域。任何未使其 DNS 緩存失效的客戶端仍將由受影響區域中的 Zuul 層進行路由。
這是故障轉移通常在 Netflix 中執行的背景信息。這個過程需要很長時間才能完成 —— 大約 45 分鐘(在狀況良好的情況下)。
使用全新進程加速響應處理
我們注意到大部分時間(大約35分鐘)都在等待應急區域擴展中。即使 AWS 可以在幾分鐘內為我們配置新實例、啟動服務、進行及時預熱,以及在 discovery 中註冊 UP 主導擴展進程之前處理其他啟動任務。
我們認為這耗時太長了。我們希望我們的故障轉移在 10 分鐘內完成。我們希望在不增加服務所有者的運營負擔的情況下這樣做。我們還希望保證開銷不變。
我們在這三個區域保留容量以吸收故障轉移流量;試想如果我們已經為所有的容量買單,為什麼不使用它呢?於是啟動了 Nimble 項目。
我們的想法是為每個微服務維護熱備份中的實例池。當我們準備進行故障轉移時,我們可以簡單地將熱備份注入集群,以接收實時通信。
未使用的預留容量稱為槽(trough)。Netflix 的一些團隊使用一些槽容量來運行批處理作業,因此我們不能簡單地將所有可用槽轉換為熱備用。相反,我們可以為我們運行的每個微服務維護一個影子集群,並將該影子集群存儲在足夠的實例中,以獲取當天的故障轉移流量。其餘的實例可供批處理作業隨意使用。
在故障轉移時,我們將實例從影子集群注入到實時集群中,而不是使用觸發 AWS 為我們配置實例的傳統擴展方法。這個過程大約需要四分鐘,而不是過去的 35 分鐘。
由於我們的容量注入很快,我們不必通過代理謹慎地移動流量以等待擴展策略做出響應。我們可以輕鬆地切換 DNS 並打開開關,從而在中斷期間減少所耗費的更多寶貴時間。
我們在陰影集群中添加了過濾器,以防止故障實例上報指標。否則,它們將汙染度量標準空間並混淆正常的操作行為。
我們還通過修改我們的 discovery 客戶端來阻止影子集群中的實例在 discovery 中註冊 UP。在我們觸發故障轉移之前,這些實例將繼續保持在不可用狀態中。
現在我們可以在七分鐘內完成區域故障轉移。 由於我們利用現有的預留容量,因此我們不會產生任何額外的基礎設施開銷。編排故障轉移的軟件是由三名工程師組成的團隊用 Python 編寫的。
關於作者
Amjith Ramanujam —— Amjith Ramanujam是Netflix的高級軟件工程師。他的團隊負責Netflix服務在極端逆境時保持運行。換句話說,他的團隊負責區域故障轉移。在他的業餘時間裡寫現代的CLI工具。他是pgcli和mycli的創始人。您可以在twitter上向他打招呼。本文由開源作者翻譯。
閱讀更多 IT技術之家 的文章