東漢末年,他們把「服務雪崩」玩到了極致(乾貨)
阿新 • • 發佈:2020-10-29
![封面](https://img-blog.csdnimg.cn/img_convert/fc9add7821f7792af46abf40e533a43c.png)
> 滾滾長江東逝水,浪花淘盡英雄。
>
> 是非成敗轉頭空。青山依舊在,幾度夕陽紅。
>
> -- 來自《三國演義》
本篇將會通過三國中的`赤壁之戰`來講述周瑜、黃蓋和諸葛亮是怎麼把`服務雪崩`玩到極致的。
本文已收錄到我的 Github,點選文末的閱讀原文開啟。給個Star吧~
> https://github.com/Jackson0714/PassJava-Learning
# 赤壁之戰
話說東漢末年,曹操、孫權、劉備在赤壁市進行了一次爭奪老大位置的大戰,這就是有名的`赤壁之戰`。
## 一、還原赤壁之戰
曹操統一北方後,南下打敗了劉備,佔領荊襄之地後,還想幹掉東邊的孫權,於是劉備和孫權一起聯合抗擊曹軍八十萬大軍。
曹操的軍隊大部分都是北方的,對於水上作戰的經驗非常欠缺,而且很多士兵暈船,於是曹操命令軍隊將`船尾用鐵索相連`,減弱了風浪顛簸,利於士兵演練。
![鐵索連環-圖片來源網路](https://img-blog.csdnimg.cn/img_convert/04c65e5e71de3f4bb92dd666b8db85a5.png)
我們來看看周瑜、黃蓋、諸葛亮的對話:
![三人對話@悟空聊架構](https://img-blog.csdnimg.cn/20201028154720430.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2phY2tzb24wNzE0,size_16,color_FFFFFF,t_70#pic_center)
>`黃蓋`:曹操是真的蠢啊,把船連著,如果船燒著了,其他船會跟著一起燒著的。鎖鏈不易解開,船都逃不了了。我們用火攻,直接把曹軍幹趴下。
`周瑜`:但如何接近他們的船呢?
`黃蓋`:我用詐降帶幾艘船出發,船上載浸油的乾草,等接近曹軍時,點燃乾草,衝向曹軍的連環船,引燃他們的船隻。
`周瑜`:秒啊!可是哪來的東風?
`諸葛亮`:我來借東風~
赤壁之戰那天,火船乘風闖入曹軍船陣,頓時一片火海。聯軍乘勢攻擊,曹軍傷亡慘重,最後以聯軍大勝結束,成為了以少勝多的經典戰役。
![引燃連鎖船-圖片來源網路](https://img-blog.csdnimg.cn/img_convert/72f8b0ab68452a9ba535aca8331154cd.png)
## 二、戰情分析
周瑜和黃蓋看出了連環船的弱點:如果一隻船被燒著了,也會把連著的船燒著。
這就很像我們的系統中出現的`服務雪崩`問題。
假定我們系統引進了微服務的思想,將多個服務進行拆分,每個服務都是通過介面呼叫來完成的,看似功能通過微服務化後,功能和職責單一,正是我們想要的.
但隨著業務的增長,服務的數量也是`隨之增多`,邏輯也會`更加複雜`,一個服務的某個邏輯需要`依賴`多個其他服務才能完成。假如一個被依賴的服務不能向上遊的服務提供服務,則很可能造成雪崩效應,最後導致整個服務不可訪問。
就像雪山上某一處出現積雪崩塌的現象,慢慢地帶動其他片區的積雪崩塌,產生了級聯反應,最後造成大片的積雪崩塌,這就是常見的雪崩場景。
**小結:** 一個服務失敗,導致整條鏈路的服務都失敗的場景,稱為服務雪崩。
那曹軍應該怎麼避免這個問題呢?別急,後面再看答案。
## 三、系統中的雪崩效應
微服務之間往往採用 RPC 或者 HTTP 呼叫,一般都會設定呼叫超時的限制,或者通過失敗重試機制來確保服務成功執行。但如果不考慮服務的熔斷和限流,還是很容易產生服務雪崩的。下面用例子來講解下雪崩效應是怎麼產生的。
![雪崩效應](https://img-blog.csdnimg.cn/img_convert/665e80380e49d3d738c98e53c016dae8.png)
- 我們系統中三個服務:`訂單服務`、`商品服務`、`庫存服務`。
- 下單場景:使用者下單了一個商品,客戶端呼叫訂單服務來生成預付款訂單,訂單服務呼叫商品服務檢視下單的哪款商品,商品服務呼叫庫存服務判斷這款商品是否有庫存,如有庫存,則可以生成預付款訂單。
- 假定因雙十一流量暴增,庫存服務不可用(如響應超時等),庫存服務收到的很多請求都未處理完,它將無法處理更多請求。
- 而上游的商品服務依賴庫存服務,商品服務的超時和重試機制會被執行。商品服務新的呼叫不斷產生,會導致商品服務的呼叫被大量積壓,產生大量的呼叫等待和重試呼叫,慢慢耗盡商品服務的資源,比如記憶體,結果導致商品服務也宕機了。
- 而訂單服務也會重走商品服務的老路。結果就是三個服務都不可用了。
## 四、造成雪崩的真實場景
### 1.4.1 服務提供者不可用
- 硬體故障,如網路故障、硬碟損壞等。
- 程式的 bug,如演算法需要佔用大量 CPU 的計算時間導致 CPU 使用率過高。
- 快取擊穿:比如應用剛重啟,短時間內快取是失效的,導致大量請求直接訪問到了資料庫,資料庫不堪重負,服務不可用。
- 秒殺和大促:服務短時間承載不了那麼多請求量。
### 1.4.2 重試加大流量
- 使用者連續重試,比如使用者看到介面上沒有響應,所以又操作了一遍,結果又增加了一倍請求量。
- 程式重試機制,比如程式碼中有多次重試的邏輯,一次失敗後,過幾秒後再重試,重試個三次就取消重試,走異常處理分支了。也是增加了請求量。
## 五、如何防止雪崩
### 方案
出問題前預防:限流、主動降級、隔離
出問題後修復:熔斷、被動降級
**本篇主要來講解熔斷機制。** 後續幾篇會講解其他方案。
## 六、熔斷原理和演算法
### 1.6.1 熔斷概念
![保險絲熔斷](https://img-blog.csdnimg.cn/img_convert/15ad816ba5ad1b171681295443592f2b.png)
熔斷這個概念來源於電路系統中的`保險絲`熔斷。當電流過大時,保險絲熔斷,防止因電流過大損壞電器元器件,或因電流過大,導致元器件熱度過高,發生火災。
![保險絲長啥樣](https://img-blog.csdnimg.cn/img_convert/71ed717390b9ebbe5fe69068e00ef506.png)
**物理公式:** 電功率 P = I^2 * R,I 代表電流,元器件的電阻 R 不變的情況下,電流越大,電功率約大,電阻做的電功大部分都用來發熱了,所以電功率越大,發熱越嚴重。(還好高中物理沒忘。)
放到我們系統中,怎麼理解熔斷?
如果在某段時間內,呼叫某個呼叫非常慢甚至超時,就可以將這個服務熔斷,後續其他服務再呼叫這個服務就直接返回,告訴其他服務:**“已經熔斷了,你別調用我了,過段時間再來試下吧。”**
### 1.6.2 如何熔斷
熔斷有個原則:一段時間內,統計失敗的次數或者失敗請求的佔比超過一定閾值,就進行熔斷。
詳細的原理如下圖所示:
![熔斷原理圖&悟空聊架構](https://img-blog.csdnimg.cn/img_convert/8bab680b9b28c7a216faeee9ffdd4ef1.png)
### 1.6.3 統計請求的演算法
- 請求訪問到後臺服務後,首先判斷熔斷開關是否開啟。
- 如果熔斷開關已開啟,則表明當前請求不能被處理。
- 如果熔斷開關未開啟,則判斷時間視窗是否已滿。
- 如果時間視窗未滿,則請求桶中的請求數加 1。
- 如果返回的響應有異常,則失敗桶的失敗數加 1,如果返回的響應沒有異常,則成功桶的成功數加 1。
- 如果時間視窗(判斷統計錯誤率)已滿,則開始判斷是否需要熔斷。
### 1.6.4 熔斷的恢復演算法
- 當熔斷後,開關切換到`斷開狀態`。
- 過一段時間後,開關切換為`半斷開狀態`(Half-Open)。半斷開狀態下,允許對應用程式的一定數量的請求可以去呼叫服務,如果呼叫成功,則認為服務可以正常訪問了,於是將開關切換為`閉合狀態`。
- 如果半斷開狀態下,還是有呼叫失敗的情況,則認為服務還沒有恢復,開關從半斷開狀態切換到`斷開狀態`。
### 1.6.5 統計失敗率的時間視窗
![統計失敗率的時間視窗@悟空聊架構](https://img-blog.csdnimg.cn/img_convert/834dbc9fb8aed9a7e9bee2c009a8ea1f.png)
- 時間視窗可以比喻為人坐在窗戶邊,看外面來往的車輛,一定時間內從窗戶外經過的車輛。
- 每次請求,都會判斷時間視窗是否已滿(如5分鐘),如果時間視窗已滿,則重新開始計時,且清理請求數/成功數/失敗數。
- 注意:第一次開始的起始時間預設為當前時間。
### 1.6.6 嘗試恢復服務的時間視窗
![嘗試恢復服務的時間視窗@悟空聊架構](https://img-blog.csdnimg.cn/img_convert/5f4345ff59e79a9fe7980d243cc83ab2.png)
- 開關為斷開的狀態,經過一定時間後,比如 1 分鐘,設定為半斷開的狀態,嘗試傳送請求檢測服務是否恢復。
- 如果已恢復,則切換狀態為關閉狀態。如果未恢復,則切換狀態為斷開的狀態,經過 1 分鐘後,重複上面的步驟。
- 這裡的時間視窗可以根據環境的執行狀態進行動態調整,比如第一次是 1 分鐘,第二次是 3 分鐘,第三次是 10 分鐘。
## 七、熔斷中介軟體
肯定有人會問了,你這上面講的原理,難道還真的自己去寫這套演算法?
**答案:是的,專案中我們自己造了一個輪子:熔斷器。**
但這裡我不推薦大家這麼做。市面上還有更優秀的開源元件供大家使用,比如阿里系的 `Sentinel`(推薦),Netflix 的 `Hystrix`(已停止更新)。
當然 Sentinel 就不在這篇講了,後續奉上~
## 八、扭轉戰局
曹操大敗是因為連鎖船的原因,那如何給曹操提供一`妙計`,助他扭轉戰局呢?
**方案有如下幾個:**
- 可以用麻繩代替鎖鏈,因繩子更容易割斷。(熔斷機制)
- 將船劃分到幾個區域,區域之間保持一定距離。(熔斷+資源隔離)
- 在湖面上提前設關卡,黃蓋過來的話,先檢查船和人,有問題不予通行。(熔斷)
![妙啊](https://img-blog.csdnimg.cn/img_convert/bb78df887b02a2acc222eec9388c3705.png)
## 九、限流、降級
本來是想在這篇把限流和降級也寫完的,發現熔斷的內容越寫越多了,那就把限流和降級放在後面幾篇吧。也是三國故事哦~
## 寫在最後
《三國演義》也是我非常喜歡的一部文學作品,書大概看了 80 %,電視劇是看完了的。
最喜歡的角色當然是軍師諸葛亮啦,還有梟雄曹操~~
我建了一個學習交流群「在群裡不說話都能進步哦~」 掃碼加我,備註[加群]
![悟空呀](https://img-blog.csdnimg.cn/2020102816105824.png#pic_center)
我的公眾號