高可用系統常用解決手段淺述

所謂可用性,是指某系統能夠提供正常服務的特性。

可用性的高低是使用不可用時間總時間的比例來衡量。不可用時間是從故障發生到故障恢復的時間。比如,可用性4個9的系統(99.99%),它一年宕機時間不能超過53分鐘(=365*24*60*(1-0.9999))。做到高可用系統,需要儘可能的減少故障發生次數縮短故障持續時間

系統可用性% 宕機時間/年 宕機時間/月 宕機時間/周 宕機時間/天
90% (1個9) 36.5 天 72 小時 16.8 小時 2.4 小時
99% (2個9) 3.65 天 7.20 小時 1.68 小時 14.4 分
99.9% (3個9) 8.76 小時 43.8 分 10.1 分鐘 1.44 分
99.99% (4個9) 52.56 分 4.38 分 1.01 分鐘 8.66 秒
99.999% (5個9) 5.26 分 25.9 秒 6.05 秒 0.87 秒

出現系統不可用的原因,一種是人爲的,比如發佈了有bug的代碼、不規範的發佈流程導致的宕機,或者網站訪問量過載造成的雪崩等;另一種則是非人爲的,由於外部系統和環境的變化造成的,比如硬盤故障、機房斷電、電纜中斷等。我們需要在複雜的外部環境下保證系統的高可用。以下總結了常用的高可用解決手段。

1.拆分

這類解決手段不是以減少不可用時間爲目的,而是以縮小故障影響面爲目的。因爲一個大的系統拆分成了幾個小的獨立模塊,一個模塊出了問題不會影響到其他的模塊,從而縮小故障的影響面。手段包括:

1.1 水平拆分

系統水平拆分成三層:接入層,服務層和數據存儲層。將有狀態和無狀態的劃分開來,接入層和服務層設計成無狀態的,存儲層是有狀態的。無狀態層的服務可以平行擴展,請求落到哪臺服務器都沒有關係。平行擴展也有利於系統容量的擴充,快速擴容應對突然爆發流量的衝擊。

1.2 垂直拆分

根據功能垂直劃分,拆成相對獨立的模塊。有的僅是服務層做了拆分,存儲層共用。更爲徹底的是,拆分與該系統的業務領域模型關聯,一個領域模型劃分成一個模塊。在數據庫層面,還可以分庫分表拆分,這樣一個庫的損壞,不會影響到其他庫。分庫分表需要增加路由邏輯,及保證路由規則的一致性。

1.3 讀寫分離

也屬於垂直拆分的一種。寫請求的依賴主庫,讀請求的依賴備庫。這樣做,當出現故障的時候,可以只有讀請求的流量,寫服務暫時關閉,從而減少了故障的影響面。但需要關注數據一致性的問題。

2.降級

這類手段不是爲了防止故障的發生,而是當故障發生後,怎麼減小故障所造成的損失。比如,系統正常時提供的服務能力是100%,出現系統故障後,我們有措施能讓系統服務能力不直接降到了0,而是還能提供部分(比如50%)的服務能力。

2.1 限流

限流,流量控制。當請求量超過系統的最大容量後,訪問延遲就會增加,超過峯值的流量會拖累整個系統,出現宕機。因此,需要提前流量控制,對於超過峯值的流量,可以直接拒絕掉或者選擇隨機拒絕。限流結合業務自定義配置優先保證核心服務的正常響應,非核心服務可直接關閉。

2.2 異步調用

系統進行拆分之後,會分成多個模塊。模塊之間的依賴有強弱之分。如果是強依賴的,那麼如果依賴方出問題了,也會受到牽連出問題。這時可以梳理整個流程的調用關係,做成弱依賴調用。弱依賴調用通過消息中間件的方式來實現

異步調用不關心返回結果,不會傳遞依賴方的錯誤,進而避免造成更大規模的不可用。

 

2.3 同步調用合理設置超時時間

對於不能異步化的,採用同步調用,需要注意設置合理的超時時間。過長的超時,會延遲結果等待時間,導致整體的鏈路調用時間延長,降低整體的QPS。

經驗值:超時時間設置成平均響應延遲的2倍

2.4 失敗重試

要區分調用失敗的類型。有些失敗是短暫偶然的(比如網絡抖動),進行重試即可。而有些失敗是確定,那麼重試反而會造成調用請求量的放大,加重對調用系統的負擔。

經驗值:重試的次數一般設爲3次,再多次的重試沒有好處。

2.5 兜底方案

在系統真的出現了不可用的時候,需要有兜底方案。比如一些提示安撫用戶,或者設置跳轉鏈接以轉移用戶的請求。

3.冗餘

冗餘,目的是避免單點故障。比如對於接入層和服務層,可以平行擴展機器部署,這樣一臺機器宕機,可以將請求轉移到其他機器。數據層的冗餘比較複雜,增加一份備份數據,需要考慮一致性的問題。按照分佈式系統的CAP理論三者不可用同時滿足的原理,爲了滿足可用性和分區容錯性,就必須犧牲一致性,因此考慮使用弱一致性、最終一致性的解決方案來解決(此類文章很多,略)。

冗餘備份有全量和增量之分,有熱備和冷備之分。冗餘可以是兩臺機器的主備冗餘,可以是多機的集羣式冗餘。從部署來看,可以是跨機架、跨機房到跨城的備份。多機複製部署,上層調用採用負載均衡策略,還需要注意負載均衡設備的單點問題。

失敗通知和失敗切換

當集羣機器某臺機器出現了故障,或者某個進程掛了,能夠快速的發現,並且告警通知出來。路由選擇器能快速的切除掉這臺機器,當恢復後又能自動的加入回來。

4.灰度發佈

有個觀點,單點發佈是可用性最大的敵人。線網出現了故障,查故障的原因,一個常用的辦法就是追查下最近是否有發過版本,比較下發布前後的代碼。

使用灰度發佈策略,發佈並且驗證沒問題後再全量發佈。灰度發佈的策略,包括搭建預發佈環境,有專用的預發佈機器;或者路由策略先摘除灰度發佈的機器,驗證正常後再加入該機器;或者採用UIN取模灰度策略,驗證沒問題後再取消灰度策略。儘量採用自動化發佈,減少人爲發佈的流程。儘量選擇在訪問量低峯時段升級,減小影響用戶羣。

回滾機制

出現問題後,能有有效的回滾機制。涉及到數據修改的,發佈後會引起髒數據的寫入,需要有可靠的回滾流程,保證髒數據的清除。

除了發佈流程外,還應該在其他開發流程上做規範,比如代碼控制,集成編譯、自動化測試、靜態代碼掃描等。

5.切換

切換之前需要做好監控。監控應該是貫穿於上述所有手段的。比如業務某個模塊訪問量要監控,依賴的調用方出問題要監控,某個機房故障了要監控,發佈了服務要監控等。監控既包括系統層面的(比如CPU、內存、網絡、IO、進程),還包括業務層面的(請求量、錯誤率、耗時)。監控的間隔需要支持到分鐘級甚至到秒級的。

監控不是目的,監控沒法保證高可用,切換纔是目的,從故障的系統切換到正常的系統才能保證可用性。比如監控到某臺機器的硬盤出問題了,那麼告警要出來,然後使用一臺新的機器替換。切換可以是自動的,也可以是人工的。人工切換會有延遲恢復的問題,但能做到準確。自動切換,會比較快速,但必須要確保切換源是正常的,否則可能會引起更加嚴重的事故。切換後,要有實時的效果反饋。

最後

高可用手段遠不止本文所述的。本文只具有理論指導意義,實際實現高可用的系統,需要結合實際業務場景和所使用的開發框架來完成。

手段 方式 內容 補充
拆分 水平拆分 將系統水平拆分爲:接入層,服務層和數據存儲層。 將有狀態和無狀態的區分開,接入層和服務層設計成無狀態,存儲層是有狀態的。
垂直拆分 根據功能垂直劃分,拆成相對獨立的模塊。 可以僅對服務層進行拆分,存儲層共用;在數據庫層面分庫分表(需增加路由邏輯,保證路由規則一致性)。
讀寫分離,寫請求的依賴主庫,讀請求的依賴備庫。 需要關注數據一致性問題。
降級 請求限流 限流,流量控制。 請求的增加會導致訪問延遲增加,超過峯值會拖垮整個系統,對超過負載的流量應選擇直接/隨機拒絕。
異步調用 強依賴會導致牽連;弱依賴則不會。弱依賴通過消息中間件的方式來實現。 異步調用不關心返回結果,不會傳遞依賴方的錯誤,可避免更大規模的不可用。
超時設置 對於不能異步化的,只能採取同步調用,那麼就需要設置合理超時時間。 同步調用的超時時間設置成平均響應延遲的2倍。
失敗重試 失敗重試是必要的,但有些場景的失敗重試反而會加重被調用方的負擔。 重試的次數一般設爲3次,再多次的重試沒有好處。
兜底方案 確實不可用時,應設置跳轉鏈接以轉移用戶的請求,以提示安撫用戶。 提高客戶體驗。
冗餘 冗餘備份 冗餘的目的是避免單點故障;備份有全量和增量之分,有熱備和冷備之分。 數據層的冗餘會帶來一致性問題,爲滿足可用性和分區容錯性,需要考慮弱一致性、最終一致性的解決辦法。
發佈 灰度發佈 使用灰度發佈策略,發佈並且驗證沒問題後再全量發佈。 配備回滾機制,出現問題後,能有有效的回滾機制。
監控 全程監控 監控應該是貫穿於上述所有手段的。 監控不是目的,監控沒法保證高可用,切換纔是目的。
發佈了83 篇原創文章 · 獲贊 36 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章