1. 程式人生 > >東漢末年,他們把「服務雪崩」玩到了極致(乾貨)

東漢末年,他們把「服務雪崩」玩到了極致(乾貨)

![封面](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) 我的公眾號