這是小卷對分佈式系統架構學習的第3篇文章,雖然知道大家都不喜歡看純技術文章,寫了也沒多少閲讀量,但是個人要成長的話,還是需要往深一點的技術上去探索的
1.為什麼需要容錯
分佈式系統的本質是不可靠的,一個大的服務集羣中,程序可能崩潰、節點可能宕機、網絡可能中斷,這些“意外情況”其實全部都在“意料之中”。故障的發生是必然的,所以需要設計一套健壯的容錯機制來應對這些問題。
容錯策略,指的是“面對故障,我們該做些什麼”;而容錯設計模式,指的是“要實現某種容錯策略,我們該如何去做”。下面介紹7種常見的容錯策略。
2.七種容錯策略
7種常見的容錯策略:故障轉移、快速失敗、安全失敗、沉默失敗、故障恢復、並行調用和廣播調用
故障轉移Failover
概念:分佈式服務中,服務會有多個副本。如果調用的服務器出現故障,系統不會直接返回失敗,而是切換到其他服務副本上,保證返回調用成功的結果。
故障轉移需要設置重試次數,並且需根據實際業務場景考慮是否設置故障轉移。示例:
現在有 Service A → Service B → Service C 這麼一條調用鏈。假設 A 的超時閾值為 100ms,而 B 調用 C 需要 60ms,然後不幸失敗了,這時候做故障轉移其實已經沒有太大意義了。因為即使B調用C故障轉移成功了,調用耗時至少增加60ms,A已經超時了,這種故障轉移對系統無利。
適用場景:讀多寫少的採集,如:電商商品查詢;對成功率要求高的採集
快速失敗Failfast
當業務場景不允許,或者服務是非冪等時,重複調用會產生髒數據,就不能用故障轉移了,需要用到快速失敗。
概念:服務在調用失敗後,立即返回錯誤,不做任何重試
示例:支付場景中,調用銀行扣款接口,返回結果是網絡異常。這時候無法區分是否已扣款了,為避免重複扣款,只能服務拋出異常報錯,不能重試
適用場景:高實時性場景、交易支付場景
缺點:調用方需有較高容錯能力
安全失敗Failsafe
服務也區分主路和旁路,旁路的特點是服務失敗了也不影響核心業務。比如spring項目中的日誌、Debug信息等。旁路邏輯不影響最終結果。因此,對這類邏輯的容錯策略就是,即使旁路邏輯失敗了,也當做正確返回。
概念:當服務調用失敗時,忽略異常並返回一個默認的結果,確保系統繼續運行。
適用場景:非核心業務場景,日誌處理、監控採集
優點:最大化保證系統穩定性
示例:java中的try-catch,Dubbo中的failsafe策略
沉默失敗Failsilent
概念:大量請求如果都等到超時才失敗,可能將系統的線程、內存、網絡資源耗盡,影響整個服務穩定性。對該場景的失敗策略是:當請求失敗後,默認服務提供者一定時間內無法提供服務了,不再向它分配流量,將錯誤隔離開來。
實際應用場景:分佈式系統中,單點故障時,流量調度系統不再給該節點分配流量,每隔5分鐘自動檢查節點是否恢復。
故障恢復Failback
不是單獨存在的,通常默認使用快速失敗+故障恢復策略
概念:故障恢復是指在服務調用失敗後,將失敗的請求異步存儲下來,存到數據庫或消息隊列中,並定時重試或補償,直到調用成功。這種方式對業務具有一定的“追溯”能力。故障恢復也需有最大重試次數限制
適用場景:實時性要求不高,數據一致性要求高的場景。如:庫存更新、訂單狀態同步
優點:提高系統最終一致性
缺點:系統需配合消息隊列,實現複雜
小結:前面5種容錯策略都是針對調用失敗後如何進行彌補的,下面2種是調用之前如何提供成功率的
並行調用Forking
概念:同時調用多個服務節點,只要任意一個節點返回成功結果即認為調用成功。對於調用結果相同或相似的服務節點,這種方式可大幅提高調用成功率。
適用場景:多副本部署場景、調用耗時長且高可用要求的場景。如:數據庫分片存儲查詢
優點:提供成功率,減少等待時間(取決於最先返回成功的節點)
缺點:增加系統開銷
廣播調用Broadcast
概念:請求發送給所有服務實例,並收集所有返回結果,要求所有請求全部成功才算成功。這種方式適用於需要對多個節點進行同步操作的場景
適用場景:刷新分佈式緩存、配置同步
優點:所有節點都能執行操作
缺點:並行執行開銷大
實現方式:Dubbo的broadcast策略支持廣播調用
7種容錯策略對比
| 容錯策略 | 優點 | 缺點 | 應用場景 |
|---|---|---|---|
| 故障轉移 | 系統自動處理,調用者對失敗信息不可見 | 會增加調用時間,也會導致額外的資源開銷 | 調用冪等服務,對調用時間不敏感的場景 |
| 快速失敗 | 調用者有失敗的處理完全控制,不依賴服務的冪等性 | 調用者必須正確處理失敗邏輯,容易引起雪崩 | 調用非冪等的服務,超時閾值較低的場景 |
| 安全失敗 | 不影響主邏輯 | 只適用於旁路調用 | 調用鏈中的旁路服務 |
| 沉默失敗 | 控制錯誤不影響全局 | 出錯的地方將有一段時間內不可用 | 頻繁超時的服務 |
| 故障恢復 | 調用失敗後自動重試,也不影響主邏輯 | 推薦用於旁路服務調用,重試任務可能堆積,重試仍然可能失敗 | 調用鏈中的旁路服務,對實時性要求不高的主邏輯 |
| 並行調用 | 儘可能在最短時間內獲得最高的成功率 | 額外消耗機器資源,大部分調用可能是無用功 | 資源充足且失效容忍度低的場景 |
| 廣播調用 | 支持同時對批量的服務提供者發起調用 | 資源消耗大,失敗概率高 | 只適用於批量操作的場景 |
面試題準備
如果一個業務系統需要調用第三方的5個接口,這5個接口中只要有3個接口返回成功了就認為成功,問如何設計並實現
周志明大佬的答覆:
我看這題是個圈套呀,大多數的架構設計題目,固定答案往往都是不對的。因為做技術設計是為了解決實際問題,不能談兵,所以方案要根據希望實現的目標而定:
如果目的是這項業務儘可能快速地完成,那就forking策略,5個一起調用,成功3個算過。
如果目的是這項業務儘可能少消耗資源,那就failfast策略,先對它們出錯概率做個先驗判斷,排序後先調用最容易出錯的,錯夠3次算失敗,後面的不執行。
如果目的是這項業務儘可能高概率地完成,那就failover策略