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