淺談一下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