Hystrix
- Hystrix 是用于處理延遲和容錯的開源庫;
- Hystrix 主要用于避免級聯(lián)故障,提高系統(tǒng)彈性;
- Hystrix 解決了由于扇出導(dǎo)致的“雪崩效應(yīng)”;
- Hystrix 的核心是“隔離術(shù)”和“熔斷機制”;
關(guān)鍵詞
- 扇出:服務(wù)的調(diào)用關(guān)系像一個思維導(dǎo)圖;
- 雪崩:下游的服務(wù)掛了,上游的所有服務(wù)都超時;某個節(jié)點掛了,所有的流量都會打在另一個節(jié)點上,導(dǎo)致另一個節(jié)點也掛了,進而導(dǎo)致更多的節(jié)點掛了;
Hystrix | 主要作用
- 服務(wù)隔離和服務(wù)熔斷;
- 服務(wù)降級、快速失敗和限流;
- 請求合并和請求緩存;
- 自帶單體和集群監(jiān)控;
Hystrix | 主要步驟

Hystrix 架構(gòu)圖.png
- 調(diào)用 Main 方法
1.1 Command
1.2 ObservableCommand -
.execute()/.queue()/.observe()/.toObservable() - 判斷有沒有請求緩存和請求合并,一定要開啟 HystrixRequestContext
- 熔斷有沒有開啟
- 限流有沒有觸發(fā)(線程池 / 信號量)
- 執(zhí)行業(yè)務(wù)方法
6.1 業(yè)務(wù)執(zhí)行有沒有失敗
6.2. 業(yè)務(wù)執(zhí)行有沒有超時 - 熔斷健康檢查
- 所有的失敗都會觸發(fā) fallback
- 業(yè)務(wù)直接返回
Hystrix | 兩種命令模式
兩種命令模式,可以分別執(zhí)行:.execute()、.queue()、.observe() 和 .toObservable()。
- HystrixCommand
.execute().queue()
- HystrixObservableCommand
.observe().toObservable()
.observe() 和 .toObservable() 的區(qū)別
-
.toObservable()的new Subscriber<String>(){...}中的onNext()可以集成正式的業(yè)務(wù)邏輯,在run()方法之外的業(yè)務(wù)邏輯; -
.observe()是 Hot 處理,在處理的過程中加載了一些東西,先執(zhí)行Command的run()方法,再加載 / 注冊 Subscriber 對象; -
.toObservable()是 Cold 處理,在執(zhí)行之前就全部加載完,然后一次執(zhí)行完,先加載 / 注冊 Subscriber 對象,再執(zhí)行Command的run()方法; -
.toObservable()每次訂閱都需要一個新的對象;
HystrixCommand 和 HystrixObservableCommand 的區(qū)別
- HystrixCommand 以隔離的形式完成
run()的調(diào)用,線程隔離; - HystrixObservableCommand 使用當前線程進行調(diào)用,信號量隔離,HystrixObservableCommand 一次可以執(zhí)行多個命令;
Hystrix | GroupKey
- GroupKey 可以給 Hystrix 做分組和報警之用;
- GroupKey 將作為線程池的默認名稱;
Hystrix | CommandKey
- Hystrix 可以不填寫 CommandKey;
- 默認 Hystrix 會通過反射類名命名 CommandKey;
- 可以在 Setter 中加入 .andCommandKey() 來命名;
Hystrix | 請求緩存
- Hystrix 支持將請求結(jié)果緩存在本地;
- 通過實現(xiàn) getCacheKey 方法來判斷,是否取出緩存;
- 請求緩存要求 Command 必須在同一個上下文中;
- 通過
.withRequestCacheEnabled(true)開啟請求緩存;
Hystrix | 請求合并
- Hystrix 支持將多個請求合并成一次請求;
- Hystrix 請求合并要求兩次請求必須足夠“近”,默認的閾值是 500ms;
- 請求合并分為局部合并和全局合并;
- Collapser 可以設(shè)置相關(guān)參數(shù);
Hystrix | 隔離術(shù)
ThreadPoolKey
- 隔離一般都會用到線程池,線程池的話,一般都會起一個名字;
- Hystrix 可以不填 ThreadPoolKey;
- 默認 Hystrix 會用 GroupKey 命名線程池;
- 在 Setter 中加入 andThreadPoolKey 進行命名;
隔離介紹
- Hystrix 提供了信號量和線程兩種隔離手段;
- 線程隔離會在單獨的線程中執(zhí)行業(yè)務(wù)邏輯;
- 信號量的話就是基于信號量模型做的隔離,信號量的隔離在調(diào)用線程(Main Thread)上執(zhí)行,但是調(diào)用的次數(shù)會做限制,超過這個次數(shù)的調(diào)用就不允許了;
隔離的好處
- 比如一個請求進來了,請求了 3 個服務(wù),3 個服務(wù)在 3 個隔離的線程中執(zhí)行,2 個執(zhí)行成功了,1 個失敗了,失敗的服務(wù)并不會影響其他線程的執(zhí)行,可以快速失敗;
Hystrix | 降級處理
降級
- 降級是一種無奈的選擇,就是俗稱的備胎;
- 比如打發(fā)票打不出來了,降級成友好的提示;
- 比如商品頁,推薦的商品顯示不出來了,將提前緩存的商品信息顯示在頁面上;
- Command 在降級的時候,需要實現(xiàn) getFallback() 方法;
- ObservableCommand 降級實現(xiàn) resumeWithFallback() 方法;
降級觸發(fā)原則
- 除了 HystrixBadRequestException 之外的異常就會被降級;
- 熔斷開啟的時候也會觸發(fā)降級;
- 線程池或信號量滿的時候會被降級;
- 業(yè)務(wù)異常會觸發(fā)降級;
- 業(yè)務(wù)超時會觸發(fā)降級;
快速失敗
- Hystrix 提供了快速失敗的機制,這個機制依賴的就是 getFallback(),當出現(xiàn)任何異常的時候,都會觸發(fā) getFallback(),getFallback() 就會把失敗的業(yè)務(wù)快速返回給前端;
- 當不實現(xiàn) getFallback() 的時候,會將異常直接拋出,這也是一種快速失??;
快速失敗的好處
- 在系統(tǒng)相互依賴調(diào)用的時候,快速失敗的存在,可以防止下游服務(wù)的不正常,卡住上游服務(wù),進一步導(dǎo)致級聯(lián)雪崩的情況;
- 如果有快速失敗,下游不正常的服務(wù)快速失敗,上游服務(wù)就不會阻塞,業(yè)務(wù)還是可以正常辦理 ;
Hystrix | 熔斷機制
熔斷器介紹
- 熔斷器是一種開關(guān),用來控制流量是否執(zhí)行業(yè)務(wù)邏輯;
- 在熔斷器打開的時候,永遠執(zhí)行 getFallback(),永遠不執(zhí)行業(yè)務(wù)邏輯;
熔斷器核心指標
熔斷器的開關(guān),要么根據(jù) 3 個指標決定開關(guān),要么強制決定開關(guān)。邏輯是這樣的:在一個快照時間窗內(nèi),請求總數(shù)達到一定數(shù)后,看錯誤率,如果錯誤率超過閾值,打開熔斷開關(guān)。
- 快照時間窗:就是一個時間段;
- 請求總數(shù)閾值:在快照時間窗內(nèi)的請求總數(shù);
- 錯誤百分比閾值:在快照時間窗內(nèi),錯誤的內(nèi)容達到一定比例,才觸發(fā)熔斷開關(guān);
熔斷器的核心

熔斷器核心.png
- 每一個格代表一段時間,比如 1s;
- 沒 10 個格會做一個匯總,就最后的白格;
- 匯總的時候,如果發(fā)現(xiàn):請求的總數(shù)到閾值了,并且錯誤率到閾值了就打開熔斷器的開關(guān);
- 這寫格是滾動的,新的一格接著隊尾,就把隊首的格丟掉;
- 然后重新計算,如果不滿足打開熔斷器的條件,就將熔斷器關(guān)閉;
熔斷器的狀態(tài)
- 開啟:所有請求對會進入 fallback 方法;
- 半開啟:在熔斷器打開的狀態(tài)下,熔斷器會將請求每個幾秒放過去一個,看看服務(wù)恢復(fù)了沒有,如果恢復(fù)了,就關(guān)閉熔斷器,如此往復(fù)循環(huán);默認情況下,熔斷器開啟 5s 之后就會進入半開啟狀態(tài);
- 關(guān)閉:正常處理業(yè)務(wù)請求;
Hystrix | 兩種應(yīng)用場景
- 隱式創(chuàng)建 HystrixCommand:影廳服務(wù)調(diào)影片服務(wù)的邏輯,被封裝在 Command 的 run() 方法內(nèi),在 run() 方法內(nèi)發(fā)送了一次 HTTP 調(diào)用;當整合了 Feign 和 Zuul 的時候,HTTP 的調(diào)用就已經(jīng)整合進 HystrixCommand 中了;
- 顯示創(chuàng)建 HystrixCommand:Controller 調(diào) Service 的邏輯被封裝在 Command 的 run() 方法內(nèi);
Hystrix Dashboard | 圖例

Hystrix Dashboard 圖例.png
Hystrix Dashboard | 缺陷
- 只能監(jiān)控 2 分鐘內(nèi)的變化,不能監(jiān)控長時間的變化,并且不夠細致;
Hystrix | 設(shè)置線程池大小
- Threadpool Size:比如系統(tǒng)的 QPS 是 3000,有 100 個節(jié)點,每個節(jié)點需要承載 30 的 QPS,請求的平均處理時間是 0.2s,那么需要的線程數(shù)就是 30 * 0.2 = 6 個線程,完了要加上 0.3~0.8 的冗余,比如線程切換之類的,差不多就是 10,Hystrix 默認的線程數(shù)量是 10,就可以承擔(dān) 30 的 QPS;
- Threadpool Size:Threadpool Size 的 1.5~2 倍就可以;
Hystrix | 常見參數(shù)
請求上下文
| 配置 | 配置描述 |
|---|---|
| requestCache.enabled | 是否開啟請求緩存,默認為true |
| requestLog.enabled | 是否開啟請求日志,默認為true |
| maxRequestsInBatch | 設(shè)置批處理中允許的最大請求數(shù) |
| timerDelayInMilliseconds | 設(shè)置批處理創(chuàng)建到執(zhí)行之間的毫秒數(shù) |
線程池相關(guān)配置
| 配置 | 配置描述 |
|---|---|
| coreSize | 配置線程池大小,默認為10 |
| keepAliveTimeMinutes | 配置核心線程數(shù)空閑時keepAlived時長,默認1分鐘 |
| maxQueueSize | 配置線程池任務(wù)隊列大小,默認為-1 |
| maximumSize | 線程池中線程的最大數(shù)量,默認值是 10 |
| queueSizeRejectionThreshold | 任務(wù)隊列的請求上線,默認值是10 |
| allowMaximumSizeToDivergeFromCoreSize | 是否開啟最大線程數(shù) |
| execution.isolation.thread.timeoutInMilliseconds | 設(shè)置超時時間 |
| execution.isolation.thread.interruptOnTimeout | 請求超時是否中斷任務(wù) |
| execution.isolation.thread.interruptOnCancel | 請求取消是否終端任務(wù) |
熔斷機制相關(guān)配置
| 配置 | 配置描述 |
|---|---|
| circuitBreaker.enabled | 是否開啟熔斷器 |
| circuitBreaker.requestVolumeThreshold | 啟用熔斷器功能窗口時間內(nèi)的最小請求數(shù) |
| circuitBreaker.sleepWindowInMilliseconds | 半熔斷開啟時間 |
| circuitBreaker.errorThresholdPercentage | 開啟熔斷的失敗率閾值 |