這是個人第 66 篇原創文章
git
做者 | 悟空聊架構github
來源 | 悟空聊架構(ID:PassJava666)web
滾滾長江東逝水,浪花淘盡英雄。是非成敗轉頭空。青山依舊在,幾度夕陽紅。算法
-- 來自《三國演義》數據庫
本篇將會經過三國中的赤壁之戰
來說述周瑜、黃蓋和諸葛亮是怎麼把服務雪崩
玩到極致的。c#
本文已收錄到個人 Github,點擊文末的閱讀原文打開。給個Star吧~緩存
https://github.com/Jackson0714/PassJava-Learning服務器
赤壁之戰
話說東漢末年,曹操、孫權、劉備在長江赤壁(今湖北蒲圻西北)進行了一次爭奪老大位置的大戰,這就是有名的赤壁之戰
。微信
1、還原赤壁之戰
曹操統一北方後,南下戰勝了劉備,佔領荊襄之地後,還想幹掉東邊的孫權,因而劉備和孫權一塊兒聯合抗擊曹軍八十萬大軍。網絡
曹操的軍隊大部分都是北方的,對於水上做戰的經驗很是欠缺,並且不少士兵暈船,因而曹操命令軍隊將船尾用鐵索相連
,減弱了風浪顛簸,利於士兵演練。
![](http://static.javashuo.com/static/loading.gif)
咱們來看看周瑜、黃蓋、諸葛亮的對話:
![](http://static.javashuo.com/static/loading.gif)
❝❞
黃蓋
:曹操是真的蠢啊,把船連着,若是船燒着了,其餘船會跟着一塊兒燒着的。鎖鏈不易解開,船都逃不了了。咱們用火攻,直接把曹軍幹趴下。周瑜
:但如何接近他們的船呢?黃蓋
:我用詐降帶幾艘船出發,船上載浸油的乾草,等接近曹軍時,點燃乾草,衝向曹軍的連環船,引燃他們的船隻。周瑜
:妙啊!但是哪來的東風?諸葛亮
:我來借東風~
赤壁之戰那天,火船乘風闖入曹軍船陣,頓時一片火海。聯軍乘勢攻擊,曹軍傷亡慘重,最後以聯軍大勝結束,成爲了以少勝多的經典戰役。
![](http://static.javashuo.com/static/loading.gif)
2、戰情分析
周瑜和黃蓋看出了連環船的弱點:「若是一隻船被燒着了,也會把連着的船燒着」 。
這就很像咱們的系統中出現的服務雪崩
問題。
假定咱們系統引進了微服務的思想,將多個服務進行拆分,每一個服務都是經過接口調用來完成的,看似功能經過微服務化後,功能和職責單一,正是咱們想要的.
但隨着業務的增加,服務的數量也是隨之增多
,邏輯也會更加複雜
,一個服務的某個邏輯須要依賴
多個其餘服務才能完成。假如一個被依賴的服務不能向上遊的服務提供服務,則極可能形成雪崩效應
,最後致使整個服務不可訪問
。
就像雪山上某一處出現積雪崩塌的現象,慢慢地帶動其餘片區的積雪崩塌,產生了級聯反應,最後形成大片的積雪崩塌,這就是常見的雪崩場景。
「小結」 一個服務失敗,致使整條鏈路的服務都失敗的場景,稱爲服務雪崩。
那曹軍應該怎麼避免這個問題呢?別急,後面再看答案。
3、系統中的雪崩效應
微服務之間每每採用 RPC 或者 HTTP 調用,通常都會設置調用超時的限制,或者經過失敗重試機制來確保服務成功執行。但若是不考慮服務的熔斷和限流,仍是很容易產生服務雪崩的。下面用例子來說解下雪崩效應是怎麼產生的。
![](http://static.javashuo.com/static/loading.gif)
-
咱們系統中三個服務:
訂單服務
、商品服務
、庫存服務
。 -
下單場景:用戶下單了一個商品,客戶端調用訂單服務來生成預付款訂單,訂單服務調用商品服務查看下單的哪款商品,商品服務調用庫存服務判斷這款商品是否有庫存,若有庫存,則能夠生成預付款訂單。
-
假定因雙十一
流量暴增
,庫存服務不可用(如響應超時等),庫存服務收到的不少請求都未處理完,它將沒法處理更多請求。 -
而上游的商品服務
依賴
庫存服務,商品服務的超時
和重試機制
會被執行。商品服務新的調用不斷產生,會致使商品服務的調用被大量積壓
,產生大量的調用等待
和重試調用
,慢慢耗盡
商品服務的資源,好比內存,結果致使商品服務也宕機了。 -
而訂單服務也會重走商品服務的老路。結果就是三個服務
都不可用了
。
4、形成雪崩的真實場景
1.4.1 服務提供者不可用
-
硬件故障:
如網絡故障、硬盤損壞等。 -
程序的 bug:
如算法須要佔用大量 CPU 的計算時間致使 CPU 使用率太高。 -
緩存擊穿:
好比應用剛重啓,短期內緩存是失效的,致使大量請求直接訪問到了數據庫,數據庫不堪重負,服務不可用。 -
秒殺和大促:
服務短期承載不了那麼多請求量。
1.4.2 重試加大流量
-
用戶連續重試:
好比用戶看到界面上沒有響應,因此又操做了一遍,結果又增長了一倍請求量。 -
程序重試機制:
好比代碼中有屢次重試的邏輯,一次失敗後,過幾秒後再重試,重試個三次就取消重試,走異常處理分支了。也是增長了請求量。
5、如何防止雪崩
方案
出問題前預防:限流、主動降級、隔離
出問題後修復:熔斷、被動降級
「本篇主要來說解熔斷機制。」 後續幾篇會講解其餘方案。
6、熔斷原理和算法
1.6.1 熔斷概念
![](http://static.javashuo.com/static/loading.gif)
熔斷這個概念來源於電路系統中的保險絲
熔斷。當電流過大時,保險絲熔斷,防止因電流過大
損壞電器元器件,或因電流過大,致使元器件熱度太高,發生火災。
![](http://static.javashuo.com/static/loading.gif)
「物理公式」 電功率 P = I^2 * R,I 表明電流,元器件的電阻 R 不變的狀況下,電流越大,電功率約大,電阻作的電功大部分都用來發熱
了,因此電功率越大,發熱越嚴重。(還好高中物理沒忘。)
放到咱們系統中,怎麼理解熔斷?
若是在某段時間內,調用某個服務很是慢甚至超時,就能夠將這個服務熔斷,後續其餘服務再調用這個服務就直接返回,告訴其餘服務:「「已經熔斷了,你別調用我了,過段時間再來試下吧。」」
1.6.2 如何熔斷
「熔斷有個原則」 一段時間內,統計失敗的次數或者失敗請求的佔比超過必定閾值,就進行熔斷。
詳細的原理以下圖所示:
![](http://static.javashuo.com/static/loading.gif)
1.6.3 統計請求的算法
-
請求訪問到後臺服務後,首先判斷熔斷開關是否打開。
-
若是熔斷開關
已打開
,則代表當前請求不能被處理。 -
若是熔斷開關
未打開
,則判斷時間窗口是否已滿。 -
若是時間窗口
未滿
,則請求桶中的請求數加 1。 -
若是返回的響應有異常,則失敗桶的
失敗數加 1
,若是返回的響應沒有異常,則成功桶的成功數加 1
。 -
若是時間窗口
已滿
,則開始判斷是否須要熔斷。
1.6.4 熔斷的恢復算法
-
當熔斷後,開關切換到
斷開狀態
。 -
過一段時間後,開關切換爲
半斷開狀態
(Half-Open)。半斷開狀態下,容許對應用程序的必定數量的請求能夠去調用服務,若是調用成功,則認爲服務能夠正常訪問了,因而將開關切換爲閉合狀態
。 -
若是半斷開狀態下,仍是有調用失敗的狀況,則認爲服務尚未恢復,開關從半斷開狀態切換到
斷開狀態
。
1.6.5 統計失敗率的時間窗口
![](http://static.javashuo.com/static/loading.gif)
-
時間窗口能夠比喻爲人坐在窗戶邊,看外面來往的車輛,必定時間內從窗戶外通過的車輛。
-
每次請求,都會判斷時間窗口是否已滿(如5分鐘),若是時間窗口已滿,則從新開始計時,且清理請求數/成功數/失敗數。
-
注意:第一次開始的起始時間默認爲當前時間。
1.6.6 嘗試恢復服務的時間窗口
![](http://static.javashuo.com/static/loading.gif)
-
開關爲斷開的狀態,通過必定時間後,好比 1 分鐘,設置爲
半斷開
的狀態,嘗試發送請求檢測服務是否恢復。 -
若是已恢復,則切換狀態爲關閉狀態。若是未恢復,則切換狀態爲
斷開
的狀態,通過 1 分鐘後,重複上面的步驟。 -
這裏的時間窗口能夠根據環境的運行狀態進行動態調整,好比第一次是 1 分鐘,第二次是 3 分鐘,第三次是 10 分鐘。
7、熔斷中間件
確定有人會問了,你這上面講的原理,難道還真的本身去寫這套算法?
「答案:是的,項目中咱們本身造了一個輪子:熔斷器。」
但這裏我不推薦你們這麼作。市面上還有更優秀的開源組件供你們使用,好比阿里系的 Sentinel
(推薦),Netflix 的 Hystrix
(已中止更新)。
固然 Sentinel 就不在這篇講了,後續奉上~
8、扭轉戰局
曹操大敗是由於連鎖船的緣由,那如何給曹操提供一妙計
,助他扭轉戰局呢?
「方案有以下幾個」
-
能夠用麻繩代替鎖鏈,因繩子更容易割斷。(熔斷機制)
-
將船劃分到幾個區域,區域之間保持必定距離,即便某個區域燒着了,也不會影響其餘區域。(熔斷+資源隔離)
-
在湖面上提早設關卡,黃蓋過來的話,先檢查船和人,有問題不予通行。(熔斷)
![](http://static.javashuo.com/static/loading.gif)
9、限流、降級
原本是想在這篇把限流
和降級
也寫完的,發現熔斷的內容越寫越多了,那就把限流和降級放在後面幾篇吧。也是三國故事哦~
寫在最後
《三國演義》也是我很是喜歡的一部文學做品,書大概看了 80 %,電視劇是看完了的。
最喜歡的角色固然是軍師諸葛亮啦,還有梟雄曹操~~
- END -
我建了一個學習交流羣「在羣裏不說話都能進步哦~」 掃碼加我,備註[加羣]
我的二維碼
更多內容
![](http://static.javashuo.com/static/loading.gif)
我是一個秒殺請求,正在逃離這顆星球...
![](http://static.javashuo.com/static/loading.gif)
若是把四個消息隊列都拉到一個羣裏,他們會聊些什麼?
![](http://static.javashuo.com/static/loading.gif)
這三年被分佈式坑慘了,曝光十大坑
點亮,服務器三年不宕機
本文分享自微信公衆號 - 悟空聊架構(PassJava666)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。