亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring?Cloud?Hystrix原理與注意事項(xiàng)小結(jié)

 更新時間:2025年03月03日 14:06:36   作者:張彥峰ZYF  
本文介紹了Hystrix的基本概念、工作原理以及其在實(shí)際開發(fā)中的應(yīng)用方式,通過對Hystrix的深入學(xué)習(xí),開發(fā)者可以在分布式系統(tǒng)中實(shí)現(xiàn)精細(xì)的錯誤處理機(jī)制,并能夠及時響應(yīng)系統(tǒng)中的異常,避免服務(wù)的連鎖崩潰,感興趣的朋友一起看看吧

Spring Cloud Hystrix是一個強(qiáng)大的容錯框架,基于Netflix Hystrix開發(fā),能夠有效隔離服務(wù)的依賴,避免單個服務(wù)的失敗影響到整個系統(tǒng)。它通過熔斷器、降級機(jī)制、線程池隔離等手段,在面對服務(wù)故障時,依然能夠確保系統(tǒng)能夠優(yōu)雅地降級,并保持服務(wù)的可用性。此外,Hystrix還支持實(shí)時監(jiān)控和告警,幫助開發(fā)者及時發(fā)現(xiàn)和處理系統(tǒng)中的問題。

本篇文章將對Spring Cloud Hystrix進(jìn)行剖析,介紹其設(shè)計理念、工作原理以及如何在實(shí)際項(xiàng)目中使用它來實(shí)現(xiàn)服務(wù)的容錯和高可用性。希望通過本文的講解,能夠幫助讀者深入理解Hystrix的核心功能和配置,掌握其在分布式系統(tǒng)中的應(yīng)用,為構(gòu)建高可用的微服務(wù)架構(gòu)打下堅實(shí)的基礎(chǔ)。

一、Spring Cloud Hystrix概述和設(shè)計目標(biāo)

(一)Spring Cloud Hystrix基本概述

在軟件架構(gòu)領(lǐng)域,容錯特指容忍并防范局部錯誤,不讓這種局部錯誤不斷擴(kuò)大。我們在識別風(fēng)險領(lǐng)域,風(fēng)險可以分為已知風(fēng)險和未知風(fēng)險,容錯直接應(yīng)對的就是已知風(fēng)險,這就要求針對的場景是:系統(tǒng)之間調(diào)用延時超時、線程的數(shù)量急劇飆升導(dǎo)致CPU使用率升高、集群服務(wù)器磁盤被打滿等等。面對容錯,我們一般都會要求提供降級方案,而且強(qiáng)調(diào)不可進(jìn)行暴力降級(比如把整個論壇功能降掉直接給用戶展現(xiàn)一個大白板),而是將一部分?jǐn)?shù)據(jù)緩存起來,也就是要有拖底數(shù)據(jù)。

在一個分布式系統(tǒng)中,必然會有部分系統(tǒng)的調(diào)用會失敗。Hystrix是一個通過添加超時容錯和失敗容錯邏輯來幫助你控制這些分布式系統(tǒng)的交互。Hystrix通過隔離服務(wù)之間的訪問,阻止他們之間的級聯(lián)故障以及提供后背選項(xiàng)來實(shí)現(xiàn)進(jìn)行丟底方案,從而提高系統(tǒng)的整體彈性。

Hystrix對應(yīng)的中文名字是“豪豬”,豪豬周身長滿了刺,能保護(hù)自己不受天敵的傷害,代表了一種防御機(jī)制,Hystrix提供了熔斷、隔離、Fallback、cache、監(jiān)控等功能,能夠在一個、或多個依賴同時出現(xiàn)問題時保證系統(tǒng)依然可用。

查看Hytrix官網(wǎng)有如下描述:

Introduction:
Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, 
services and 3rd party libraries, 
stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.

大意是:Hystrix是一個延遲和容錯庫,旨在隔離遠(yuǎn)程系統(tǒng)、服務(wù)和第三方庫,阻止級聯(lián)故障,在復(fù)雜的分布式系統(tǒng)中實(shí)現(xiàn)恢復(fù)能力。

(二)Spring Cloud Hystrix概述設(shè)計目標(biāo)

查看Hystrix官網(wǎng)Home · Netflix/Hystrix Wiki · GitHub中對設(shè)計目標(biāo)有如下描述:

Hystrix is designed to do the following:
1.Give protection from and control over latency and failure from dependencies accessed 
(typically over the network) via third-party client libraries.
2.Stop cascading failures in a complex distributed system.
3.Fail fast and rapidly recover.
4.Fallback and gracefully degrade when possible.
5.Enable near real-time monitoring, alerting, and operational control.

翻譯如下:

  • 1.通過客戶端庫對延遲和故障進(jìn)行保護(hù)和控制。
  • 2.在一個復(fù)雜分布式系統(tǒng)中防止級聯(lián)故障。
  • 3.快速失敗和迅速恢復(fù)。
  • 4.在合理情況下回退和優(yōu)雅降級。
  • 5.開啟近實(shí)時監(jiān)控、告警和操作控制。

二、Spring Cloud Hystrix解決的主要內(nèi)容

(一)隔離(線程池隔離和信號量隔離)

在微服務(wù)架構(gòu)中,要求服務(wù)的容錯隔離,以及對應(yīng)的回退降級限流方案理論,我們在以下博客中已經(jīng)初步提到:微服務(wù)架構(gòu)服務(wù)可靠性分析

隔離的基本要求是:限制調(diào)用分布式服務(wù)的資源使用,某一個調(diào)用的服務(wù)出現(xiàn)問題不會影響其他服務(wù)調(diào)用。Spring Cloud Hystrix下針對隔離主要指的是線程池隔離和信號量隔離。如下圖所示,可以很明顯的說明信號量隔離和線程池隔離的主要區(qū)別:線程池方式下,業(yè)務(wù)請求線程和執(zhí)行依賴的服務(wù)線程不是同一個線程;信號量方式下業(yè)務(wù)請求線程和執(zhí)行依賴的線程是同一個線程。

1.線程和線程池

線程隔離指每個服務(wù)都為一個個獨(dú)立的線程組,當(dāng)某個服務(wù)出現(xiàn)問題時,不會導(dǎo)致整個服務(wù)癱瘓。由于線程隔離會帶來線程開銷,有些場景(比如無網(wǎng)絡(luò)請求場景)可能會因?yàn)橛瞄_銷換隔離得不償失,為此hystrix提供了信號量隔離,當(dāng)服務(wù)的并發(fā)數(shù)大于信號量閾值時將進(jìn)入fallback。

如下圖,客戶端(第三方,網(wǎng)絡(luò)調(diào)用等)依賴和請求線程運(yùn)行在不同的線程上,可以將他們從調(diào)用線程隔離開來,這樣調(diào)用者就可以從一個耗時太長的依賴中隔離,也可以為不同的請求開啟不同的線程池,彼此之間不相互干擾。

傳統(tǒng)上,我們在實(shí)現(xiàn)線程池隔離的手段上,一般有以下兩種方式:

  • 方式一:使用一個大的線程池,固定線程池的大小,比如1000,通過權(quán)重的思路為某個方法分配一個固定大小的線程數(shù),比如為某個方法請求分配了10個線程,按照實(shí)現(xiàn)方式有“保守型”和“限制性”,具體見以后博客中和github中的代碼舉例。
  • 方式二:利用ConcurrentHashMap來存儲線程池,key是方法名,值是每個方法對應(yīng)的一個ThreadPool。當(dāng)請求到來的時候,我們獲取方法名,然后直接從Map對象中取到響應(yīng)的線程池去處理。

對于方法一而言,嚴(yán)格意義上講,它并不屬于線程池隔離,因?yàn)樗挥幸粋€公共的線程池,然后來讓大家瓜分,不過也達(dá)到了隔離的效果。在Spring Cloud Hystrix的線程池隔離上,我們使用的是方式二。對于以上兩種方式,線程池的粒度都是作用在方法上,我們可以結(jié)合實(shí)際情況也可以按組來分。

線程隔離的好處

整個應(yīng)用在客戶端調(diào)用失效的情況下也能健康的運(yùn)行,線程池能夠保證這個線程的失效不會影響應(yīng)用的運(yùn)行。當(dāng)失效的客戶端調(diào)用回復(fù)的時候,這個線程池也會被清理并且應(yīng)用會立馬回復(fù)健康,比tomcat那種長時間的恢復(fù)要好很多。簡而言之,線程隔離能夠允許在不引起中斷的情況下優(yōu)雅的處理第三方調(diào)用的各種問題。

線程隔離的缺點(diǎn)

主要缺點(diǎn)是增加了上下文切換的開銷,每個執(zhí)行都涉及到隊列,調(diào)度和上下文切換。不過NetFix在設(shè)計這個系統(tǒng)的時候,已經(jīng)決定接受這筆開銷,以換取他的好處。對于不依賴網(wǎng)絡(luò)訪問的服務(wù),比如只依賴內(nèi)存緩存,就不適合用線程池隔離技術(shù),而是采用信號量隔離。

2.信號量隔離(Semaphores)

可以使用信號量(或者計數(shù)器)來限制當(dāng)前依賴調(diào)用的并發(fā)數(shù),而不是使用線程池或者隊列。如果客戶端是可信的,且能快速返回,可以使用信號量來代替線程隔離,降低開銷。信號量的大小可以動態(tài)調(diào)節(jié),線程池卻不行。

HystrixCommand和HystrixObserverCommand提供信號量隔離在下面兩個地方:

  • Fallback:當(dāng)Hystrix檢索fallback的時候,他心總是調(diào)用tomcat線程上執(zhí)行此操作
  • 如果你設(shè)置execution.isolation.strategy為SEMAPHORE的時候,Hystrix會使用信號量代替線程池去限制當(dāng)前調(diào)用Command的并發(fā)數(shù)。

對于不依賴網(wǎng)絡(luò)訪問的服務(wù),就不適合使用線程池隔離,而是采用信號量隔離。

(二)優(yōu)雅的降級機(jī)制

超時降級、資源不足時(線程或信號量)降級,降級總之是一種退而求其次的方式,所謂降級,就是指在Hystrix執(zhí)行費(fèi)核心鏈路功能失敗的情況下,我們應(yīng)該如何返回的問題,根據(jù)業(yè)務(wù)場景的不同,一般采用以下兩種模式進(jìn)行降級:

  • 第一種:(最常用)如果服務(wù)失敗,則我們通過fallback進(jìn)行降級,返回靜態(tài)值。
  • 第二種:調(diào)用備選方案

降級會退的方案有很多,以上只是初步的建議,具體降級回退方案如:Fail Fast(快速失敗)、Fail Silent(無聲失敗)、Fallback:Static(返回默認(rèn)值)、Fallback:Stubbed(自己組裝一個值返回)、Fallback:Cache via Network(利用遠(yuǎn)程緩存)、Primary + Secondary with fallback(主次方式回退),其基本的實(shí)現(xiàn)在相關(guān)功能由介紹,建議進(jìn)行擴(kuò)展學(xué)習(xí)。

這里需要注意回退處理方式不適合的場景,如以下三種場景我們不可以使用回退處理:

  • 寫操作
  • 批處理
  • 計算

(三)熔斷器

當(dāng)失敗率達(dá)到閥值自動觸發(fā)降級(如因網(wǎng)絡(luò)故障/超時造成的失敗率高),熔斷器觸發(fā)的快速失敗會進(jìn)行快速恢復(fù),類似于電閘。下圖是基本源碼中的一個處理流程圖:

斷路器打開還是關(guān)閉的步驟如下

1.假定請求的量超過預(yù)定的閾值(circuitBreakerRequestVolumeThreshold)
2.再假定錯誤百分比超過了設(shè)定的百分比(circuitBreakerErrorThresholdPercentage)
3.斷路器會從close狀態(tài)到open狀態(tài)
4.當(dāng)打開的狀態(tài),會短路所有針對該斷路器的請求
5.過了一定時間(circuitBreakerSleepWindowInMilliseconds(短路超過一定時間會重新去請求)),下一個請求將通過,不會被短路(當(dāng)前是half-open狀態(tài))。如果這個請求失敗了,則斷路器在睡眠窗口期間返回open狀態(tài),如果請求成功,則斷路器返回close狀態(tài),并重新回到第一步邏輯判斷。

(四)緩存

提供了請求緩存、請求合并實(shí)現(xiàn)。

1.Hystrix緩存策略的命令執(zhí)行流程                       

2.請求合并實(shí)現(xiàn)

為什么要進(jìn)行請求合并?舉個例子,有個礦山,每過一段時間都會生產(chǎn)一批礦產(chǎn)出來(質(zhì)量為卡車載重量的1/100),卡車可以一等到礦產(chǎn)生產(chǎn)出來就馬上運(yùn)走礦產(chǎn),也可以等到卡車裝滿再運(yùn)走礦產(chǎn),

前者一次生產(chǎn)對應(yīng)卡車一次往返,卡車需要往返100次,而后者只需要往返一次,可以大大減少卡車往返次數(shù)。顯而易見,利用請求合并可以減少線程和網(wǎng)絡(luò)連接,開發(fā)人員不必單獨(dú)提供一個批量請求接口就可以完成批量請求。

 在Hystrix中進(jìn)行請求合并也是要付出一定代價的,請求合并會導(dǎo)致依賴服務(wù)的請求延遲增高,延遲的最大值是合并時間窗口的大小,默認(rèn)為10ms,當(dāng)然我們也可以通過hystrix.collapser.default.timerDelayInMilliseconds屬性進(jìn)行修改,如果請求一次依賴服務(wù)的平均響應(yīng)時間是20ms,那么最壞情況下(合并窗口開始是請求加入等待隊列)這次請求響應(yīng)時間就會變成30ms。在Hystrix中對請求進(jìn)行合并是否值得主要取決于Command本身,高并發(fā)度的接口通過請求合并可以極大提高系統(tǒng)吞吐量,從而基本可以忽略合并時間窗口的開銷,反之,并發(fā)量較低,對延遲敏感的接口不建議使用請求合并。

請求合并的流程圖如下:                  

可以看出Hystrix會把多個Command放入Request隊列中,一旦滿足合并時間窗口周期大小,Hystrix會進(jìn)行一次批量提交,進(jìn)行一次依賴服務(wù)的調(diào)用,通過充寫HystrixCollapser父類的mapResponseToRequests方法,將批量返回的請求分發(fā)到具體的每次請求中。

(五)支持實(shí)時監(jiān)控、報警、控制(修改配置)

通過儀表盤等進(jìn)行統(tǒng)計后,從而進(jìn)行實(shí)時監(jiān)控、報警、控制,最終依據(jù)這些來修改配置,得到最佳的選擇。

三、Spring Cloud Hystrix工作流程介紹

基本流程圖如下:

1.創(chuàng)建HystrixCommand或者HystrixObservableCommand對象。用來表示對以來服務(wù)的請求操作。從命名就能看的出來,使用的是命令模式,其中HystrixCommand返回的是單個操作結(jié)果,HystrixObservableCommand返回多個結(jié)果
2.命令執(zhí)行,共有4中方法執(zhí)行命令:

  • execute():用戶執(zhí)行,從依賴的服務(wù)里返回單個結(jié)果或拋出異常
  • queue():異步執(zhí)行,直接返回一個Future對象
  • observe():放回observable對象,代表了多個結(jié)果,是一個Hot Observableto
  • Observable():返回Observable對象,但是是一個 Cold Observable(Hystrix大量的使用了RxJava,想更容易的理解Hystrix的,請自行百度RxJava進(jìn)行閱讀。)

3.結(jié)果是否被緩存。如果已經(jīng)啟用了緩存功能,且被命中,那么緩存就會直接以O(shè)bservable對象返回
4.斷路器是否已打開,沒有命中緩存,在執(zhí)行命令前會檢查斷路器是否已打開:

  • 斷路器已打開,直接執(zhí)行fallback
  • 斷路器關(guān)閉,繼續(xù)往下執(zhí)行

5.線程池And信號量Or請求隊列是否已被占滿    如果與該命令有關(guān)的線程池和請求隊列,或者信號量已經(jīng)被占滿,就直接執(zhí)行fallback
6.執(zhí)行HystrixObservableCommand.construct () 或 HystrixCommand.run()  方法。如果設(shè)置了當(dāng)前執(zhí)行時間超過了設(shè)置的timeout,則當(dāng)前處理線程會拋出一個TimeoutyException,如果命令不在自身線程里執(zhí)行,就會通過單獨(dú)的計時線程來拋出異常,Hystrix會直接執(zhí)行fallback邏輯,并忽略run或construct的返回值。
7.計算斷路器的健康值。
8.fallback處理。
9.返回成功的響應(yīng)。

四、儀表盤講解

Spring Cloud Hystrix Dashboard是一個可以監(jiān)控HystrixCommand的可視化圖形界面,由于某種原因,如網(wǎng)絡(luò)延遲、服務(wù)故障等,這時候可以借助dashboard提供的可視化界面監(jiān)控各個Hystrix執(zhí)行的成功率、調(diào)用成功數(shù)、失敗數(shù)量、最近十分鐘的流量圖等等,根據(jù)這些數(shù)據(jù)我們就可以進(jìn)行錯誤排查以及進(jìn)行服務(wù)的優(yōu)化等。Hystrix Dashboard只能對單個服務(wù)進(jìn)行監(jiān)控,實(shí)際項(xiàng)目中,服務(wù)通常集群部署,這時候可以借助Turbine進(jìn)行多個服務(wù)的監(jiān)控。

(一)監(jiān)控單體應(yīng)用

不管是監(jiān)控單體應(yīng)用還是Turbine集群監(jiān)控,我們都需要一個Hystrix Dashboard,當(dāng)然我們可以在要監(jiān)控的單體應(yīng)用上繼續(xù)添加功能,讓它也具備儀表盤的功能,但是這樣并不符合我們微服務(wù)的思想,所以,Hystrix儀表盤我還是單獨(dú)創(chuàng)建一個新的工程專門用來做Hystrix Dashboard。Hystrix Dashboard儀表盤是根據(jù)系統(tǒng)一段時間內(nèi)發(fā)生的請求情況來展示的可視化面板,這些信息時每個HystrixCommand執(zhí)行過程中的信息,這些信息是一個指標(biāo)集合和具體的系統(tǒng)運(yùn)行情況。如Hystrix Dashboard界面圖:       

輸入相關(guān)數(shù)據(jù),得到如下儀表盤:    

(二)Turbine集群監(jiān)控

在實(shí)際應(yīng)用中,我們要監(jiān)控的應(yīng)用往往是一個集群,這個時候我們就得采取Turbine集群監(jiān)控了。Turbine有一個重要的功能就是匯聚監(jiān)控信息,并將匯聚到的監(jiān)控信息提供給Hystrix Dashboard來集中展示和監(jiān)控。

在實(shí)際項(xiàng)目中,這種實(shí)時監(jiān)控有點(diǎn)耗性能,通常采用消息中間件如RabbitMQ等,我們接口調(diào)用把Hystrix的一些信息收集到RabbitMQ中,然后Turbine從RabbitMQ中獲取監(jiān)控的數(shù)據(jù)。

五、Spring Cloud Hystrix配置說明

以下的屬性都是spring cloud 1.5.9版本的。

1.Execution相關(guān)的屬性的配置:

  • hystrix.command.default.execution.isolation.strategy 隔離策略,默認(rèn)是Thread, 可選Thread|Semaphore
  • hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 命令執(zhí)行超時時間,默認(rèn)1000ms
  • hystrix.command.default.execution.timeout.enabled 執(zhí)行是否啟用超時,默認(rèn)啟用true
  • hystrix.command.default.execution.isolation.thread.interruptOnTimeout 發(fā)生超時是是否中斷,默認(rèn)true
  • hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests 最大并發(fā)請求數(shù),默認(rèn)10,該參數(shù)當(dāng)使用ExecutionIsolationStrategy.SEMAPHORE策略時才有效。如果達(dá)到最大并發(fā)請求數(shù),請求會被拒絕。理論上選擇semaphore size的原則和選擇thread size一致,但選用semaphore時每次執(zhí)行的單元要比較小且執(zhí)行速度快(ms級別),否則的話應(yīng)該用thread。

semaphore應(yīng)該占整個容器(tomcat)的線程池的一小部分。

2.Fallback相關(guān)的屬性

這些參數(shù)可以應(yīng)用于Hystrix的THREAD和SEMAPHORE策略

  • hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests 如果并發(fā)數(shù)達(dá)到該設(shè)置值,請求會被拒絕和拋出異常并且fallback不會被調(diào)用。默認(rèn)10
  • hystrix.command.default.fallback.enabled 當(dāng)執(zhí)行失敗或者請求被拒絕,是否會嘗試調(diào)用hystrixCommand.getFallback() 。默認(rèn)true

3.Circuit Breaker相關(guān)的屬性

  • hystrix.command.default.circuitBreaker.enabled 用來跟蹤circuit的健康性,如果未達(dá)標(biāo)則讓request短路。默認(rèn)true。
  • hystrix.command.default.circuitBreaker.requestVolumeThreshold 一個rolling window內(nèi)最小的請求數(shù)。如果設(shè)為20,那么當(dāng)一個rolling window的時間內(nèi)(比如說1個rolling window是10秒)收到19個請求,即使19個請求都失敗,也不會觸發(fā)circuit break。默認(rèn)20。這個參數(shù)非常重要,熔斷器是否打開首先要滿足這個條件。
  • hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds 觸發(fā)短路的時間值,當(dāng)該值設(shè)為5000時,則當(dāng)觸發(fā)circuit break后的5000毫秒內(nèi)都會拒絕request,也就是5000毫秒后才會關(guān)閉circuit。默認(rèn)5000
  • hystrix.command.default.circuitBreaker.errorThresholdPercentage錯誤比率閥值,如果錯誤率>=該值,circuit會被打開,并短路所有請求觸發(fā)fallback。默認(rèn)50
  • hystrix.command.default.circuitBreaker.forceOpen 強(qiáng)制打開熔斷器,如果打開這個開關(guān),那么拒絕所有request,默認(rèn)false
  • hystrix.command.default.circuitBreaker.forceClosed 強(qiáng)制關(guān)閉熔斷器 如果這個開關(guān)打開,circuit將一直關(guān)閉且忽略circuitBreaker.errorThresholdPercentage

4.Metrics相關(guān)參數(shù)

  • hystrix.command.default.metrics.rollingStats.timeInMilliseconds 設(shè)置統(tǒng)計的時間窗口值的,毫秒值,circuit break 的打開會根據(jù)1個rolling window的統(tǒng)計來計算。若rolling window被設(shè)為10000毫秒,則rolling window會被分成n個buckets,每個bucket包含success,failure,timeout,rejection的次數(shù)的統(tǒng)計信息。默認(rèn)10000
  • hystrix.command.default.metrics.rollingStats.numBuckets 設(shè)置一個rolling window被劃分的數(shù)量,若numBuckets=10,rolling window=10000,那么一個bucket的時間即1秒。必須符合rolling window % numberBuckets == 0。默認(rèn)10
  • hystrix.command.default.metrics.rollingPercentile.enabled 執(zhí)行時是否enable指標(biāo)的計算和跟蹤,默認(rèn)true
  • hystrix.command.default.metrics.rollingPercentile.timeInMilliseconds 設(shè)置rolling percentile window的時間,默認(rèn)60000
  • hystrix.command.default.metrics.rollingPercentile.numBuckets 設(shè)置rolling percentile window的numberBuckets。邏輯同上。默認(rèn)6
  • hystrix.command.default.metrics.rollingPercentile.bucketSize 如果bucket size=100,window=10s,若這10s里有500次執(zhí)行,只有最后100次執(zhí)行會被統(tǒng)計到bucket里去。增加該值會增加內(nèi)存開銷以及排序的開銷。默認(rèn)100
  • hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds 記錄health 快照(用來統(tǒng)計成功和錯誤綠)的間隔,默認(rèn)500ms

5.Request Context 相關(guān)參數(shù)

hystrix.command.default.requestCache.enabled 默認(rèn)true,需要重載getCacheKey(),返回null時不緩存
hystrix.command.default.requestLog.enabled 記錄日志到HystrixRequestLog,默認(rèn)true

6.Collapser Properties 相關(guān)參數(shù)

hystrix.collapser.default.maxRequestsInBatch 單次批處理的最大請求數(shù),達(dá)到該數(shù)量觸發(fā)批處理,默認(rèn)Integer.MAX_VALUE
hystrix.collapser.default.timerDelayInMilliseconds 觸發(fā)批處理的延遲,也可以為創(chuàng)建批處理的時間+該值,默認(rèn)10
hystrix.collapser.default.requestCache.enabled 是否對HystrixCollapser.execute() and HystrixCollapser.queue()的cache,默認(rèn)true

7.ThreadPool 相關(guān)參數(shù)

線程數(shù)默認(rèn)值10適用于大部分情況(有時可以設(shè)置得更?。?,如果需要設(shè)置得更大,那有個基本得公式可以follow:
requests per second at peak when healthy × 99th percentile latency in seconds + some breathing room
每秒最大支撐的請求數(shù) (99%平均響應(yīng)時間 + 緩存值)
比如:每秒能處理1000個請求,99%的請求響應(yīng)時間是60ms,那么公式是:
1000 (0.060+0.012)

基本得原則時保持線程池盡可能小,他主要是為了釋放壓力,防止資源被阻塞。
當(dāng)一切都是正常的時候,線程池一般僅會有1到2個線程激活來提供服務(wù)

  • hystrix.threadpool.default.coreSize 并發(fā)執(zhí)行的最大線程數(shù),默認(rèn)10
  • hystrix.threadpool.default.maxQueueSize BlockingQueue的最大隊列數(shù),當(dāng)設(shè)為-1,會使用SynchronousQueue,值為正時使用LinkedBlcokingQueue。該設(shè)置只會在初始化時有效,之后不能修改threadpool的queue size,除非reinitialising thread executor。默認(rèn)-1。
  • hystrix.threadpool.default.queueSizeRejectionThreshold 即使maxQueueSize沒有達(dá)到,達(dá)到queueSizeRejectionThreshold該值后,請求也會被拒絕。因?yàn)閙axQueueSize不能被動態(tài)修改,這個參數(shù)將允許我們動態(tài)設(shè)置該值。if maxQueueSize == -1,該字段將不起作用
  • hystrix.threadpool.default.keepAliveTimeMinutes 如果corePoolSize和maxPoolSize設(shè)成一樣(默認(rèn)實(shí)現(xiàn))該設(shè)置無效。如果通過plugin(https://github.com/Netflix/Hystrix/wiki/Plugins)使用自定義實(shí)現(xiàn),該設(shè)置才有用,默認(rèn)1.
  • hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds 線程池統(tǒng)計指標(biāo)的時間,默認(rèn)10000
  • hystrix.threadpool.default.metrics.rollingStats.numBuckets 將rolling window劃分為n個buckets,默認(rèn)10

六、Spring Cloud Hystrix線程調(diào)整和計算

在實(shí)際使用過程中會涉及多個微服務(wù),可能有些微服務(wù)使用的線程池過大,有些服務(wù)使用的線程池小,有些服務(wù)的超時時間長,有的短,所以Hystrix官方也提供了一些方法供我們來計算和調(diào)整這些配置,總的宗旨是,通過自我預(yù)判的配置先發(fā)布到生產(chǎn)或測試,然后查看它具體的運(yùn)行情況,在調(diào)整為更符合業(yè)務(wù)的配置,通常做法有:

1.超過時間默認(rèn)為1000ms,如果業(yè)務(wù)明顯超過1000ms,則根據(jù)自己的業(yè)務(wù)進(jìn)行修改。

2.線程池默認(rèn)10,如果知道確實(shí)要使用更多時可以調(diào)整。

3.金絲雀發(fā)布,如果成功則保持。

4.在生產(chǎn)環(huán)境中運(yùn)行超過24小時。

5.如果系統(tǒng)有告警和監(jiān)控,那么可以依靠他們捕捉問題。

6.運(yùn)行24小時后,通過延時百分位和流量來計算有意義的最低滿足值。

7.在生產(chǎn)或測試環(huán)境中實(shí)時修改值,然后用儀表盤監(jiān)控。

8.如果斷路器產(chǎn)生變化和影響,則需要再次確認(rèn)這個配置。                             

官方例子如圖,Threadpool的大小為10,如下計算公式:

每秒請求的峰值 X 99%的延遲百分比(請求響應(yīng)的時間)+ 預(yù)留緩存的值

即 30 x 0.2s  = 6 + 預(yù)留緩存的值 = 10 ,這里預(yù)留了4個線程數(shù)。

Thread Timeout:預(yù)留了一個足夠的時間,250ms,然后加上重試一次的中位數(shù)值。

Connect Timeout & Read Timeout:100ms和250ms,這兩個值的設(shè)置方法遠(yuǎn)高于中位數(shù)值,以適應(yīng)大多數(shù)請求。

在實(shí)際的生產(chǎn)測試過程中,配置每個服務(wù)時可以根據(jù)官方推薦的這些方法來測試自己的業(yè)務(wù)需要的數(shù)值,這樣產(chǎn)生最合適的配置。

七、Spring Cloud Hystrix源碼分析

Spring Cloud Hystrix的使用: 

  • 1.啟動類添加@EnableHystrix注解。 
  • 2.方法上添加@HystrixCommand注解,并指定fallback的方法。

查看@EnableHystrix注解

/**
 * Convenience annotation for clients to enable Hystrix circuit breakers (specifically).
 * Use this (optionally) in case you want discovery and know for sure that it is Hystrix
 * you want. All it does is turn on circuit breakers and let the autoconfiguration find
 * the Hystrix classes if they are available (i.e. you need Hystrix on the classpath as
 * well).
 *
 * @author Dave Syer
 * @author Spencer Gibb
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@EnableCircuitBreaker
public @interface EnableHystrix {
}

這個注解的功能就是開啟Hystrix。這個注解還引入了@EnableCircuitBreaker注解。

在代碼同一級目錄下,還可以看到兩個配置類:HystrixAutoConfiguration和HystrixCircuitBreakerConfiguration。 
下面是HystrixAutoConfiguration配置類的配置:

@Configuration
@ConditionalOnClass({ Hystrix.class, HealthIndicator.class })
@AutoConfigureAfter({ HealthIndicatorAutoConfiguration.class })
public class HystrixAutoConfiguration {
    @Bean
    @ConditionalOnEnabledHealthIndicator("hystrix")
    public HystrixHealthIndicator hystrixHealthIndicator() {
        return new HystrixHealthIndicator();
    }
}

從代碼中可以看到,HystrixAutoConfiguration這個配置類主要是hystrix的健康檢查的配置。再看下HystrixCircuitBreakerConfiguration這個類,這個類里面就配置了很多內(nèi)容。

@Bean
public HystrixCommandAspect hystrixCommandAspect() {
    return new HystrixCommandAspect();
}

這里返回了HystrixCommandAspect的bean,這個切面中定義了Pointcut:

@Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)")
public void hystrixCommandAnnotationPointcut() {
}
@Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)")
public void hystrixCollapserAnnotationPointcut() {
}

所以,這個Aspect就是利用AOP切面對 HystrixCommand 、 HystrixCollapser 兩種注解的方法進(jìn)行擴(kuò)展處理。 
我們在方法上添加@HystrixCommand注解,就會經(jīng)過這個切面,這個切面中定義了@Around(…)攔截所有請求。

下面看下這個方法:

@Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()")
public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {
    Method method = getMethodFromTarget(joinPoint);
    Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint);
    if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) {
        throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " +
                "annotations at the same time");
    }
    MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));
    MetaHolder metaHolder = metaHolderFactory.create(joinPoint);
    HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);
    ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?
            metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();
    Object result;
    try {
        result = CommandExecutor.execute(invokable, executionType, metaHolder);
    } catch (HystrixBadRequestException e) {
        throw e.getCause();
    }
    return result;
}

這個方法中,一開始先獲取攔截的Method,然后判斷,如果方法上同時加了@HystrixCommand和@HystrixCollapser兩個注解的話,就拋異常。 
在創(chuàng)建MetaHolder的時候,調(diào)用了MetaHolderFactory的create方法,MetaHolderFactory有兩個子類,CollapserMetaHolderFactory和CommandMetaHolderFactory,最終執(zhí)行的是子類的create方法,下面是CommandMetaHolderFactory中的create方法:

private static class CommandMetaHolderFactory extends MetaHolderFactory {
    @Override
    public MetaHolder create(Object proxy, Method method, Object obj, Object[] args, final ProceedingJoinPoint joinPoint) {
        HystrixCommand hystrixCommand = method.getAnnotation(HystrixCommand.class);
        ExecutionType executionType = ExecutionType.getExecutionType(method.getReturnType());
        MetaHolder.Builder builder = metaHolderBuilder(proxy, method, obj, args, joinPoint);
        return builder.defaultCommandKey(method.getName())
                        .hystrixCommand(hystrixCommand)
                        .observableExecutionMode(hystrixCommand.observableExecutionMode())
                        .executionType(executionType)
                        .observable(ExecutionType.OBSERVABLE == executionType)
                        .build();
    }
}
MetaHolder.Builder metaHolderBuilder(Object proxy, Method method, Object obj, Object[] args, final ProceedingJoinPoint joinPoint) {
    MetaHolder.Builder builder = MetaHolder.builder()
            .args(args).method(method).obj(obj).proxyObj(proxy)
            .defaultGroupKey(obj.getClass().getSimpleName())
            .joinPoint(joinPoint);
    if (isCompileWeaving()) {
        builder.ajcMethod(getAjcMethodFromTarget(joinPoint));
    }
    FallbackMethod fallbackMethod = MethodProvider.getInstance().getFallbackMethod(obj.getClass(), method);
    if (fallbackMethod.isPresent()) {
        fallbackMethod.validateReturnType(method);
        builder
                .fallbackMethod(fallbackMethod.getMethod())
                .fallbackExecutionType(ExecutionType.getExecutionType(fallbackMethod.getMethod().getReturnType()));
    }
    return builder;
}

在創(chuàng)建MetaHolder的過程中,就會指定fallback方法。 
創(chuàng)建完MetaHolder之后,就會根據(jù)MetaHolder創(chuàng)建HystrixInvokable。

public HystrixInvokable create(MetaHolder metaHolder) {
    HystrixInvokable executable;
    if (metaHolder.isCollapserAnnotationPresent()) {
        executable = new CommandCollapser(metaHolder);
    } else if (metaHolder.isObservable()) {
        executable = new GenericObservableCommand(HystrixCommandBuilderFactory.getInstance().create(metaHolder));
    } else {
        executable = new GenericCommand(HystrixCommandBuilderFactory.getInstance().create(metaHolder));
    }
    return executable;
}

這段代碼里定義了后續(xù)真正執(zhí)行HystrixCommand的GenericCommand實(shí)例

方法最終會去執(zhí)行CommandExecutor.execute方法:

public static Object execute(HystrixInvokable invokable, ExecutionType executionType, MetaHolder metaHolder) throws RuntimeException {
    Validate.notNull(invokable);
    Validate.notNull(metaHolder);
    switch (executionType) {
        case SYNCHRONOUS: {
            return castToExecutable(invokable, executionType).execute();
        }
        case ASYNCHRONOUS: {
            HystrixExecutable executable = castToExecutable(invokable, executionType);
            if (metaHolder.hasFallbackMethodCommand()
                    && ExecutionType.ASYNCHRONOUS == metaHolder.getFallbackExecutionType()) {
                return new FutureDecorator(executable.queue());
            }
            return executable.queue();
        }
        case OBSERVABLE: {
            HystrixObservable observable = castToObservable(invokable);
            return ObservableExecutionMode.EAGER == metaHolder.getObservableExecutionMode() ? observable.observe() : observable.toObservable();
        }
        default:
            throw new RuntimeException("unsupported execution type: " + executionType);
    }
}

這里會分成同步和異步的場景,進(jìn)入execute方法看下:

/**
 * Used for synchronous execution of command.
 * 
 * @return R
 *         Result of {@link #run()} execution or a fallback from {@link #getFallback()} if the command fails for any reason.
 * @throws HystrixRuntimeException
 *             if a failure occurs and a fallback cannot be retrieved
 * @throws HystrixBadRequestException
 *             if invalid arguments or state were used representing a user failure, not a system failure
 * @throws IllegalStateException
 *             if invoked more than once
 */
public R execute() {
    try {
        return queue().get();
    } catch (Exception e) {
        throw decomposeException(e);
    }
}

這個方法的注釋中說明了返回值,可以返回請求的結(jié)果,當(dāng)失敗的時候,則會通過getFallback()方法來執(zhí)行一個回退操作,由于是GenericCommand實(shí)例,那就看下這個實(shí)例中的getFallback()方法:

@Override
protected Object getFallback() {
    if (getFallbackAction() != null) {
        final CommandAction commandAction = getFallbackAction();
        try {
            return process(new Action() {
                @Override
                Object execute() {
                    MetaHolder metaHolder = commandAction.getMetaHolder();
                    Object[] args = createArgsForFallback(metaHolder, getExecutionException());
                    return commandAction.executeWithArgs(commandAction.getMetaHolder().getFallbackExecutionType(), args);
                }
            });
        } catch (Throwable e) {
            LOGGER.error(FallbackErrorMessageBuilder.create()
                    .append(commandAction, e).build());
            throw new FallbackInvocationException(e.getCause());
        }
    } else {
        return super.getFallback();
    }
}

大體的一個流程也就知道了,就是通過HystrixCommandAspect,請求成功返回接口的結(jié)果,請求失敗執(zhí)行fallback的邏輯。

八、總結(jié)

在現(xiàn)代微服務(wù)架構(gòu)中,服務(wù)的高可用性和穩(wěn)定性是系統(tǒng)設(shè)計的核心要素之一。Spring Cloud Hystrix作為一個優(yōu)秀的容錯框架,通過熔斷器、線程池隔離和降級策略,為我們提供了一套有效的解決方案來應(yīng)對服務(wù)調(diào)用中的各種異常情況。通過合理使用Hystrix,我們能夠確保在某個服務(wù)出現(xiàn)故障時,依賴它的其他服務(wù)不會受到影響,從而實(shí)現(xiàn)整個系統(tǒng)的健壯性和彈性。

本文介紹了Hystrix的基本概念、工作原理以及其在實(shí)際開發(fā)中的應(yīng)用方式。通過對Hystrix的深入學(xué)習(xí),開發(fā)者可以在分布式系統(tǒng)中實(shí)現(xiàn)精細(xì)的錯誤處理機(jī)制,并能夠及時響應(yīng)系統(tǒng)中的異常,避免服務(wù)的連鎖崩潰。盡管Hystrix在一些場景下已經(jīng)被新的技術(shù)替代(如Resilience4j),但它依然在許多老舊系統(tǒng)中扮演著重要角色,是微服務(wù)容錯設(shè)計的經(jīng)典實(shí)踐之一。

總之,Spring Cloud Hystrix為我們提供了一個有效的框架來保障微服務(wù)架構(gòu)中的高可用性和彈性,它的設(shè)計理念和實(shí)現(xiàn)方式仍然值得我們在現(xiàn)代開發(fā)中借鑒和使用。希望通過本文的講解,讀者能夠深入理解Hystrix的精髓,掌握如何在項(xiàng)目中應(yīng)用它,為構(gòu)建健壯的分布式系統(tǒng)提供有力支持。

到此這篇關(guān)于Spring Cloud Hystrix原理與注意事項(xiàng)的文章就介紹到這了,更多相關(guān)Spring Cloud Hystrix內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java agent使用全解析

    java agent使用全解析

    這篇文章主要介紹了javaagent的相關(guān)資料,文中示例代碼非常詳細(xì),供大家參考和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • Springboot筆記之熱部署及不生效的解決方案

    Springboot筆記之熱部署及不生效的解決方案

    這篇文章主要介紹了Springboot筆記之熱部署及不生效的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 使用Java制作一個簡單的記事本

    使用Java制作一個簡單的記事本

    本文給大家?guī)淼氖鞘褂肑ava制作一個簡單的記事本的代碼,有相同需要的朋友可以參考下
    2015-02-02
  • Spring IOC相關(guān)注解運(yùn)用(上篇)

    Spring IOC相關(guān)注解運(yùn)用(上篇)

    這篇文章主要介紹了Spring?IOC相關(guān)注解的運(yùn)用,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-05-05
  • myeclipse創(chuàng)建servlet_動力節(jié)點(diǎn)Java學(xué)院整理

    myeclipse創(chuàng)建servlet_動力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要為大家詳細(xì)介紹了myeclipse創(chuàng)建servlet的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Java實(shí)現(xiàn)線程安全單例模式的五種方式的示例代碼

    Java實(shí)現(xiàn)線程安全單例模式的五種方式的示例代碼

    這篇文章主要介紹了Java中實(shí)現(xiàn)線程安全單例模式的五種方式:餓漢式、枚舉單例、懶漢式、DCL懶漢式和靜態(tài)內(nèi)部類懶漢單例,感興趣的可以了解一下
    2022-03-03
  • Spring基礎(chǔ)篇之初識DI和AOP

    Spring基礎(chǔ)篇之初識DI和AOP

    這篇文章主要為大家詳細(xì)介紹了Spring基礎(chǔ)篇之初識DI和AOP,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • java 抽象類和接口的區(qū)別詳細(xì)解析

    java 抽象類和接口的區(qū)別詳細(xì)解析

    abstractclass和interface是Java語言中對于抽象類定義進(jìn)行支持的兩種機(jī)制,正是由于這兩種機(jī)制的存在,才賦予了Java強(qiáng)大的面向?qū)ο竽芰?需要了解的朋友可以參考下
    2012-11-11
  • java對象初始化順序驗(yàn)證示例

    java對象初始化順序驗(yàn)證示例

    以下這段小程序?qū)φ{(diào)用對象構(gòu)造函數(shù)時,父類構(gòu)造函數(shù)、成員變量初始化函數(shù),以及非靜態(tài)初始化塊調(diào)用順序進(jìn)行驗(yàn)證,不考慮靜態(tài)成員及靜態(tài)初始化塊
    2014-02-02
  • java.net.MalformedURLException異常的解決方法

    java.net.MalformedURLException異常的解決方法

    下面小編就為大家?guī)硪黄猨ava.net.MalformedURLException異常的解決方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05

最新評論