淺談一下SpringCloud中Hystrix服務(wù)熔斷和降級原理
在分布式系統(tǒng)架構(gòu)中,如果一個應(yīng)用不能對來自依賴的故障進行隔離,那該應(yīng)用本身就處在被拖垮的風(fēng)險中。 因此,為了構(gòu)建穩(wěn)定、可靠的分布式系統(tǒng),我們的服務(wù)應(yīng)當(dāng)具有自我保護能力,當(dāng)依賴服務(wù)不可用時,當(dāng)前服務(wù)啟動自我保護功能,從而避免發(fā)生雪崩效應(yīng)。在分布式微服務(wù)系統(tǒng)設(shè)計時,要使用一定的降級策略,來保證當(dāng)服務(wù)提供方不可用時,服務(wù)調(diào)用方可以切換到降級后的策略進行處理。Hystrix 作為熔斷器組件,其使用范圍還是很廣泛的。本文簡單介紹下 Hystrix 的原理。
一、Hystrix 是什么?
Hystrix 是 Netflix 的一款開源的容錯框架,通過服務(wù)隔離來避免由于依賴延遲、異常,引起資源耗盡導(dǎo)致系統(tǒng)不可用的解決方案。
二、Hystrix 可以做什么?
Hystrix 被設(shè)計用來做了下面幾件事:
- 保護系統(tǒng)間的調(diào)用延時以及錯誤,特別是通過第三方工具的網(wǎng)絡(luò)調(diào)用
- 阻止錯誤在分布式系統(tǒng)之前的傳播
- 快速失敗和迅速恢復(fù)
- 錯誤回退和優(yōu)雅的服務(wù)降級
三、Hystrix 解決了什么問題?
- 限制調(diào)用分布式服務(wù)的資源使用,某一個調(diào)用的服務(wù)出現(xiàn)問題不會影響其他服務(wù)調(diào)用,通過線程池隔離和信號量隔離實現(xiàn)。
- Hystrix 提供了優(yōu)雅降級機制:超時降級、資源不足時(線程或信號量)降級,降級后可以配合降級接口返回兜底數(shù)據(jù)。
- Hystrix 提供了熔斷器實現(xiàn),當(dāng)失敗率達到閥值自動觸發(fā)降級(如因網(wǎng)絡(luò)故障/超時造成的失敗率高),熔斷器觸發(fā)的快速失敗會進行快速恢復(fù)等。
四、Hystrix遵循的設(shè)計原則
- 防止任何單獨的依賴耗盡資源(線程)
- 過載立即切斷并快速失敗,防止排隊
- 盡可能提供回退以保護用戶免受故障
- 使用隔離技術(shù)(例如隔板,泳道和斷路器模式)來限制任何一個依賴的影響
- 通過近實時的指標,監(jiān)控和告警,確保故障被及時發(fā)現(xiàn)
- 通過動態(tài)修改配置屬性,確保故障及時恢復(fù)
- 防止整個依賴客戶端執(zhí)行失敗,而不僅僅是網(wǎng)絡(luò)通信
五、Hystrix 的工作流程
下圖描述了使用 Hystrix 的一次請求調(diào)用服務(wù)層的流程?!緢D片來源于:Hystrix 官方文檔,點擊看大圖】
Hystrix 整個工作流如下:
- 構(gòu)造一個 HystrixCommand 或 HystrixObservableCommand 對象,用于封裝請求,并在構(gòu)造方法配置請求被執(zhí)行需要的參數(shù);
- 執(zhí)行命令,Hystrix提供了多種執(zhí)行命令的方法(詳見本文第六章);
- 判斷是否使用緩存響應(yīng)請求,若啟用了緩存,且緩存可用,直接使用緩存響應(yīng)請求。Hystrix 支持請求緩存,但需要用戶自定義啟動;
- 判斷熔斷器是否打開(熔斷器有3種狀態(tài),詳見第七章),如果打開,跳到第8步;
- 判斷線程池/隊列/信號量是否已滿,已滿則跳到第8步;
- 執(zhí)行 HystrixObservableCommand.construct() 或 HystrixCommand.run(),如果執(zhí)行失敗或者超時,跳到第8步;否則,跳到第9步;
- 統(tǒng)計熔斷器監(jiān)控指標;
- 走Fallback備用邏輯;
- 返回請求響應(yīng)。從流程圖上可知道,第5步線程池/隊列/信號量已滿時,還會執(zhí)行第7步邏輯,更新熔斷器統(tǒng)計信息,而第6步無論成功與否,都會更新熔斷器統(tǒng)計信息。
六、Hystrix 執(zhí)行命令的幾種方法
Hystrix 提供了4種執(zhí)行命令的方法,execute() 和 queue() 適用于 HystrixCommand 對象,而 observe() 和toObservable() 適用于 HystrixObservableCommand 對象。
execute() 以同步堵塞方式執(zhí)行 run(),只支持接收一個值對象。Hystrix 會從線程池中取一個線程來執(zhí)行 run(),并等待返回值。
queue() 以異步非阻塞方式執(zhí)行 run(),只支持接收一個值對象。調(diào)用 queue() 就直接返回一個 Future 對象。可通過 Future.get() 拿到 run() 的返回結(jié)果,但 Future.get() 是阻塞執(zhí)行的。若執(zhí)行成功,F(xiàn)uture.get() 返回單個值。當(dāng)執(zhí)行失敗時,如果沒有重寫 fallback,F(xiàn)uture.get() 拋出異常。
observe() 事件注冊前執(zhí)行 run() / construct(),支持接收多個值對象,取決于發(fā)射源。調(diào)用 observe() 會返回一個 hot Observable,也就是說,調(diào)用 observe() 自動觸發(fā)執(zhí)行 run() / construct(),無論是否存在訂閱者。
如果繼承的是 HystrixCommand,Hystrix 會從線程池中取一個線程以非阻塞方式執(zhí)行 run();如果繼承的是HystrixObservableCommand,將以調(diào)用線程阻塞執(zhí)行 construct()。
observe() 使用方法:
- 調(diào)用 observe() 會返回一個 Observable 對象;
- 調(diào)用這個 Observable 對象的 subscribe() 方法完成事件注冊,從而獲取結(jié)果。
toObservable() 事件注冊后執(zhí)行 run() / construct(),支持接收多個值對象,取決于發(fā)射源。調(diào)用 toObservable() 會返回一個 cold Observable,也就是說,調(diào)用 toObservable() 不會立即觸發(fā)執(zhí)行 run() / construct(),必須有訂閱者訂閱 Observable 時才會執(zhí)行。
如果繼承的是 HystrixCommand,Hystrix 會從線程池中取一個線程以非阻塞方式執(zhí)行 run(),調(diào)用線程不必等待run();如果繼承的是 HystrixObservableCommand,將以調(diào)用線程堵塞執(zhí)行 construct(),調(diào)用線程需等待construct() 執(zhí)行完才能繼續(xù)往下走。
toObservable() 使用方法:
- 調(diào)用 observe() 會返回一個Observable對象;
- 調(diào)用這個 Observable 對象的 subscribe() 方法完成事件注冊,從而獲取結(jié)果。
需注意的是,HystrixCommand 也支持 toObservable() 和 observe(),但是即使將 HystrixCommand 轉(zhuǎn)換成Observable,它也只能發(fā)射一個值對象。只有 HystrixObservableCommand 才支持發(fā)射多個值對象。
七、熔斷器的三種狀態(tài)
Hystrix 提供的熔斷器具有自我反饋,自我恢復(fù)的功能,Hystrix會根據(jù)調(diào)用接口的情況,讓熔斷器在closed,open,half-open 三種狀態(tài)之間自動切換。
- open 狀態(tài):說明打開熔斷,也就是服務(wù)調(diào)用方執(zhí)行本地降級策略,不進行遠程調(diào)用。
- closed 狀態(tài):說明關(guān)閉了熔斷,這時候服務(wù)調(diào)用方直接發(fā)起遠程調(diào)用。
- half-open 狀態(tài):是一個中間狀態(tài),當(dāng)熔斷器處于這種狀態(tài)時,直接發(fā)起遠程調(diào)用。
三種狀態(tài)的轉(zhuǎn)換:
closed → open:正常情況下熔斷器為 closed 狀態(tài),當(dāng)訪問同一個接口次數(shù)超過設(shè)定閾值并且錯誤比例超過設(shè)置錯誤閾值的時候,就會打開熔斷機制,這時候熔斷器狀態(tài)從 closed → open。
open → half-open:當(dāng)服務(wù)接口對應(yīng)的熔斷器狀態(tài)為 open 狀態(tài)時候,所有服務(wù)調(diào)用方調(diào)用該服務(wù)方法時候都是執(zhí)行本地降級方法,那么什么時候才會恢復(fù)到遠程調(diào)用呢?Hystrix 提供了一種測試策略,也就是設(shè)置了一個時間窗口,從熔斷器狀態(tài)變?yōu)?open 狀態(tài)開始的一個時間窗口內(nèi),調(diào)用該服務(wù)接口時候都委托服務(wù)降級方法進行執(zhí)行。如果時間超過了時間窗口,則把熔斷狀態(tài)從 open → half-open,這時候服務(wù)調(diào)用方調(diào)用服務(wù)接口時,就可以發(fā)起遠程調(diào)用而不再使用本地降級接口,如果發(fā)起遠程調(diào)用還是失敗,則重新設(shè)置熔斷器狀態(tài)為open狀態(tài),從新記錄時間窗口開始時間。
half-open → closed:當(dāng)熔斷器狀態(tài)為 half-open,這時候服務(wù)調(diào)用方調(diào)用服務(wù)接口時候,就可以發(fā)起遠程調(diào)用而不再使用本地降級接口,如果發(fā)起遠程調(diào)用成功,則重新設(shè)置熔斷器狀態(tài)為 closed 狀態(tài)。
用來判斷熔斷器從 closed → open 轉(zhuǎn)換的數(shù)據(jù)是 HystrixCommandMetrics 對象來做的,該對象用來存HystrixCommand 的一些指標數(shù)據(jù),比如接口調(diào)用次數(shù),調(diào)用接口失敗的次數(shù)等等。
八、Hystrix 幾種容錯方案
- 隔離模式(線程池隔離、信號量隔離)
對不同類型的請求使用線程池來資源隔離,每種類型的請求互不影響,如果一種類型的請求線程資源耗盡,則對后續(xù)的該類型請求直接返回,不再調(diào)用后續(xù)資源。 - 熔斷模式
如果某個目標服務(wù)調(diào)用慢或者有大量超時,此時,熔斷該服務(wù)的調(diào)用,對于后續(xù)調(diào)用請求,不再繼續(xù)調(diào)用目標服務(wù),而是調(diào)用降級服務(wù)返回數(shù)據(jù),快速釋放資源。如果目標服務(wù)情況好轉(zhuǎn)則恢復(fù)調(diào)用。 - 限流模式
上述的熔斷模式和隔離模式都屬于出錯后的容錯處理機制,而限流模式則可以稱為預(yù)防模式。限流模式主要是提前對各個類型的請求設(shè)置最高的QPS閾值,若高于設(shè)置的閾值則對該請求直接返回,不再調(diào)用后續(xù)資源。這種模式不能解決服務(wù)依賴的問題,只能解決系統(tǒng)整體資源分配問題,因為沒有被限流的請求依然有可能造成雪崩效應(yīng)。
隔離模式一般使用兩種:
- 線程池隔離模式
使用一個線程池來存儲當(dāng)前的請求,線程池對請求作處理,設(shè)置任務(wù)返回處理超時時間,堆積的請求堆積入線程池隊列。這種方式需要為每個依賴的服務(wù)申請線程池,有一定的資源消耗,好處是可以應(yīng)對突發(fā)流量(流量洪峰來臨時,處理不完可將數(shù)據(jù)存儲到線程池隊列慢慢處理)。 - 信號量隔離模式
使用一個原子計數(shù)器(或信號量)來記錄當(dāng)前有多少個線程在運行,請求來了的話,先判斷計數(shù)器的數(shù)值,若超過設(shè)置的最大數(shù)值則丟棄該類型的新請求,若不超過則執(zhí)行計數(shù)操作請求,使計數(shù)器 +1,請求返回則計數(shù)器 -1。這種方式是嚴格的控制線程且立即返回模式,無法應(yīng)對突發(fā)流量(流量洪峰來臨時,處理的線程超過數(shù)量,其他的請求會直接返回,不繼續(xù)去請求依賴的服務(wù))。
到此這篇關(guān)于淺談一下SpringCloud中Hystrix服務(wù)熔斷和降級原理的文章就介紹到這了,更多相關(guān)Hystrix服務(wù)熔斷和降級原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java代理模式(靜態(tài)代理、動態(tài)代理、cglib代理)
代理(Proxy)是一種設(shè)計模式,提供了對目標對象另外的訪問方式;這篇文章主要介紹了Java 中的三種代理模式,需要的朋友可以參考下,希望能給你帶來幫助2021-07-07SpringBoot3中token攔截器鏈的設(shè)計與實現(xiàn)步驟
本文介紹了spring boot后端服務(wù)開發(fā)中有關(guān)如何設(shè)計攔截器的思路,文中通過代碼示例和圖文講解的非常詳細,具有一定的參考價值,需要的朋友可以參考下2024-03-03最新hadoop安裝教程及hadoop的命令使用(親測可用)
這篇文章主要介紹了最新hadoop安裝教程(親測可用),本文主要講解了如何安裝hadoop、使用hadoop的命令及遇到的問題解決,需要的朋友可以參考下2022-06-06