Hystrix(斷路器)學習筆記

一、Hystrix簡介

1.1、分佈式系統面臨的問題

複雜的分佈式系統的應用程序有數十個依賴關係,每個依賴關係在某些時候將不可避免的失敗。

對於高併發的系統,若某個依賴系統出問題會導致系統瞬時飽和,也會導致服務間的延遲增加,隊列、線程和其他系統資源緊張,從而導致系統發生更多級聯故障。

上述問題表示需要對系統的故障進行隔離,以達到單個依賴關係失敗,不影響整個系統的目的。

1.2、Hystrix是什麼

Hystrix是一個用於處理分佈式系統的延遲和容錯的開源庫。
在分佈式系統裏,許多依賴不可避免的會調用失敗,如超時、異常等,Hystrix能夠保證在一個依賴出現問題的時候,不會導致整體服務失敗,避免級聯故障,以提高分佈式系統的彈性。

1.3、Hystrix能幹什麼

Hystrix能幹的事情主要有:

  • 服務隔離、降級、熔斷、限流、快速失敗
  • 請求合併、請求緩存
  • 接近實時的監控

1.4、Hystrix的設計原則

  • 防止任何單獨的依賴使用容器(如Tomcat)所有的用戶線程。
  • 切斷負載並快速失敗,而不是排隊。
  • 儘可能提供回退以保護用戶受故障。
  • 使用隔離技術(如艙壁、泳道、斷路器模式)來限制任何一個依賴的影響。
  • 通過接近實時的指標,監控和報警,優化發現時間。
  • 通過配置更改的低延遲傳播,優化恢復時間。
  • 防止各種客戶端執行失敗,而不僅僅是網絡通信。

二、java項目直接使用Hystrix

2.1、加入依賴

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-hystrix</artifactId> 
</dependency>

官方示例:https://github.com/Netflix/Hystrix/wiki/How-To-Use

2.2、基本使用(直接在java中引入jar)

2.2.1、HystrixCommand和HystrixObservableCommand

1、前者的命令邏輯寫在run(); 後者的命令邏輯寫在construct() 。
2、前者的run()是由新創建的線程執行; 後者的construct()是由調用程序線程執行。
3、前者一個實例只能向調用程序發送單條數據,比如上面例子中run()只能返回一個String結果; 後者一個實例可以順序發送多條數據,可以順序調用多個onNext(),便實現了向調用程序發送多條數據。

2.2.2、命令執行方法

execute(), queue(), observe(), toObservable() 這四個方法來觸發執行 run()/construct(), 一個實例只能執行一次這4個方法,注意:HystrixObservableCommand沒有execute()和queue()。

1、execute():以同步阻塞的方式執行run()。調用exectue()後,Hystrix先創建一個新線程運行run(),接着調用程序要在execute()調用處一致阻塞着,直到run()運行完成。

2、queue():以異步非阻塞方式執行run()。一調用queue(),就直接返回一個future對象,同時Hystrix創建一個新線程運行run(), 調用程序通過Future.get()拿到run()返回結果,而Future.get()是阻塞執行的。

3、observe():事件註冊前執行run()/construct():
第一步是事件註冊前,先調用observe()自動觸發執行run()/construct():如果繼承的時HystrixCommand, hystrix將創建新線程非阻塞執行run();如果繼承的時HystrixObservableCOmmand,將以調用程序線程阻塞執行construct()。
第二部是從observe()返回迪歐澳洋程序調用subscribe()完成事件註冊,如果run()/construct()執行成本,則觸發onNext()和onCompleted(),如果執行異常則觸發onError()。

4、toObservable():事件註冊後執行run()/construct():
第一步是事件註冊前,一調用toObservable()方法就直接返回一個Observable對象
第二部調用subscribe()完成事件註冊後自動觸發執行run()/construct(): 如果繼承的時HystrixCommand, hystrix將創建新線程非阻塞執行run(), 調用程序不必等待run(); 如果繼承的時HystrixObservableCommand, 將以調用程序線程阻塞執行construct(), 調用程序等待construct()執行完才能繼續往下走,如果run()/construct()執行成功,則觸發onNext()和onCompleted(), 如果執行異常則觸發onError()。

2.2.3、命令名稱

默認情況下,命令名是從類名派生的:getClass(), getSimpleName(): 要明確地定義名字,通過HystrixCommand或HystrixObservableCommand構造函數傳入,例如:

super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HelloWorld1"))
.andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld")
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(HelloWorldPool")));

1、GroupKey: 是HystrixCommand不可缺少的配置,其他配置均爲可選,例如:

super(HystrixCommandGroupKey.Factory.asKey("HelloWorld1");

HystrixCommandGroupKey的作用有2個:

  • 起到分組監控、報警的作用
  • 是在不配置HystrixThreadPoolKey的情況下,起到分組線程池的作用。即默認使用HystrixCommandGroupKey去命名線程池。使用同一個HystrixCommandGroupKey且沒有自定義HystrixThreadPoolKey的HystrixCommand將使用同一個線程池。

2、commandKey:命令的標識名稱

3、ThreadPoolKey:線程池的標識名稱。

2.2.4、Command Thread Pool 設置

雖然HystrixCommandGroupKey可以起到隔離線程池的作用,但無法起到對線程池進行精細配置的作用。這裏就需要線程池進行配置,例如:

super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HelloWorld1")) .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("MyThreadPool")) .andThreadPoolPropertiesDefaults(
HystrixThreadPoolProperties.Setter() .withCoreSize(20) .withKeepAliveTimeMinutes(1)
                           .withMaxQueueSize(-1)
)
.andCommandPropertiesDefaults( HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(100)
) );

1、andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(“MyThreadPool”)) 這是配置ThreadPoolKey。如果需要在同一個GroupKey下面配置不同的ThreadPool,就需要這個配置。

2、andThreadPoolPropertiesDefaults 表示設置線程池默認的屬性值,包括:
1)withCoreSize(20):用來配置線程池大小,不配置的話使用的默認值是10。
2)withKeepAliveTimeMinutes(1):用來配置核心線程數空閒時keep alive的時長,默認 1 mins,一般不需要修改。
3)withMaxQueueSize(-1):配置線程池任務隊列的大小,默認值爲-1,表示SynchronousQueue將被使用,即意味着其實這個隊列只是一個交換器,任務將直接交給工作線程處理。如果工作線程不足,那任務將被拒絕;如果使用任務正整數,LinkedBlockingQueue將被使用。

2.2.5、使用注意事項

編寫完自己的Command智慧,使用的時候,每次都需要new一個新對象,再調用execute()方法。注意:不要調用run()方法,否則熔斷、隔離等功能是不生效的。

2.2.6、錯誤傳播

run()裏面拋出的HystrixBadRequestException只用於計數,方法拋出的所有其他異常都作爲失敗,會觸發getFallBack()和斷路器邏輯。
你可以包裝你想要拋出的異常,HystrixBadRequestException適用的情況,如舉報非法參數或非系統故障,不會計入失敗的指標,不會觸發回退邏輯。

2.2.7、快速失敗

快速失敗是指沒有重寫getFallBack,遇到異常後直接拋出,程序停止運行。

2.2.8、回退/降級

所謂降級,指在Hystrix執行非核心鏈路功能失敗的情況下,我們如何處理,比如我們返回默認值等。觸發時,會調用fallback設置降級方法,在降級方法中,可以設置默認的降級返回數據。
使用fallback機制很簡單,繼承HystrixCommand只需要重新getFallback(),繼承HystrixObservableCommand只需要重新resumeWithFallback().

如下情況將會觸發回退:

  • 非HystrixBadRequestException異常
  • run()/construct()異常
  • 熔斷器啓動
  • 線程池/信號量已滿

2.2.9、請求緩存

Hystrix支持將一個請求結果緩存起來,下一個具有相同key的請求將直接從緩存中取出結果,減少請求開銷。使用方式如下:

  • 通過getCacheKey()在一個HystrixCommand或一個HystrixObservableCommand對象上實現該方法來啓動請求緩存。
  • 另外要求這多個請求必須在同一個上下文。通過HystrixRequestContext.initialContext()和context.shutdown()可以創建一個context,這兩條語句間的所有請求都處於同一個context。
  • 通過isResponseFromCache()可檢測返回結果是否來自緩存。

2.2.10、合併請求

Hystrix支持n個請求自動合併爲一個請求,這將是多次網絡交互變爲一次,極大節省開銷。注意一點,兩個請求能自動合併的前提是兩者足夠”近“,即兩者啓動執行的間隔時長要足夠小,默認爲10ms,即超過10ms將不自動合併。
Hystrix支持2中請求合併方式:請求範圍和全局範圍。這是在collapser構造中配置的,默認爲request-scoped。請求範圍是指在一個HystrixRequestContexts上下文中的請求;全局範圍指跨HystrixRequestContexts的請求。

三、SpringCloud中使用Hystrix

3.1、加入依賴

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-hystrix</artifactId> </dependency>
<dependency>
	<groupId>org.springframework.boot</groupId> 
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> 
</dependency>

3.2、啓動類上添加

@SpringBootApplication
@EnableHystrixDashboard
@EnableCircuitBreaker
@EnableHystrix

3.3、在Controller的方法上添加Hystrix配置

@HystrixCommand(fallbackMethod = "error", commandProperties = {
@HystrixProperty(name="execution.isolation.strategy", value = "THREAD"),
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "4000"),
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value =50") }, threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "1"),
@HystrixProperty(name = "maxQueueSize", value = "10"),
@HystrixProperty(name = "keepAliveTimeMinutes", value = "1000"), @HystrixProperty(name = "queueSizeRejectionThreshold", value = "8"), @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"), @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1500")
})

Hystrix支持兩種方式定義HystrixCommand,一種是將類繼承自HystrixCommand類,並重寫run方法;另一種是在方法頭上寫註解的方式,使用註解的方式代碼會比較清晰,將Hystrix代碼和業務代碼隔離開。

3.4、Hystrix的Dashboard

3.4.1、概述

Hystrix自帶了Dashboard,如果監控單個實例,可以很方便的通過Hystrix的dashboard進行查看運行情況,直接進入http://localhost:8080/hystrix

Hystrix Dashboard共支持三種不同的監控方式,依次爲:

  • 默認的集羣監控:通過 http://turbine-hostname:port/turbine.stream開啓,實現對默認集羣的監控。
  • 指定的集羣監控:通過 http://turbine- hostname:port/turbine.stream?cluster=[clusterName] 開啓,實現對clusterName集羣的監控。
  • 單體應用的監控:通過 http://hystrix-app:port/hystrix.stream 開啓,實現對具體某個服務實例的監控。

前兩者都對集羣的監控,需要整合Turbine才能實現。

例子如下:
在這裏插入圖片描述
說明如下:
1、delay:該參數用來控制服務器上輪詢監控信息的延遲時間,默認爲2000毫秒,可以通過配置該屬性來降低客戶端的網絡和CPU消耗。
2、title:該參數對應了頭部標題Hystrix Stream之後的內容,默認會使用具體監控實例的url,可以通過配置該信息來展示更合適的標題。
3、監控信息的左上部分找到兩個重要的圖形信息:一個實心圓和一條曲線:

  • 實心圓:共有兩種含義:它通過顏色的變化代表了實例的健康程度,它的監控度從綠色、黃色、橙色、紅色遞減。該實心圓出了顏色的變化之外,它的大小也會根據實例的請求流量發生變化,流量越大該實心圓就越大。所以通過該實心圓的展示,就可以在大量的實例中快速的發現故障實例和高壓力實例。
  • 曲線:用來記錄2分鐘內的流量相對變化,可以通過它來觀察到流量的上升和下降趨勢。

3.5、Hystrix的參數配置

3.5.1、屬性配置

Hystrix使用Netflix的配置管理庫Archaius作爲配置屬性的默認實現。官方配置文檔:https://github.com/Netflix/Hystrix/wiki/Configuration

每個屬性有四個優先級,依次增大:
1、代碼的全局默認值
2、動態全局默認屬性:可以使用全局屬性文件來更改全局默認屬性
3、代碼示例默認:定義特定於實例的默認值,比如在HystrixCommand構造函數中設置的值。
4、動態實例屬性:可以動態設置實例特定的值,從而覆蓋前面三個默認級別,格式是:hystrix.command.命令key.屬性名稱=值

3.5.2、請求上下文

1、requestCache.enabled:設置是否開啓請求的緩存功能,默認爲true
2、requestLog.enabled:設置是否開啓請求的日誌功能,默認爲true

3.5.3、命令執行

1、execution.isolation.strategy
指示HystrixCommand.run()執行哪個隔離策略,選項:

  • THREAD:它在單獨的線程上執行,併發請求受線程池中的線程數限制
  • SEMAPHORE:它在調用線程上執行,併發請求受信號計數的限制

說明:

  • 官方推薦使用線程隔離策略,默認也是按照線程隔離進行處理
  • 信號量隔離的方式是限制了總的併發數,每一次請求過了,請求線程和調用依賴服務的線程是同一個線程,那麼如果不設計遠程RPC調用(沒有網絡開銷)則使用信號量來隔離,更爲輕量,開銷更小。
  • 信號量的大小可以動態調整,線程池的大小不可用動態調整
  • 配置示例:
@HystrixCommand(fallbackMethod = "error", commandProperties = {
@HystrixProperty(name="execution.isolation.strategy", value = "THREAD") })

2、execution.isolation.thread.timeoutInMilliseconds
表示請求線程總超時時間,如果超過這個設置的時間,hystrix就會調用fallback方法。value爲毫秒,默認爲1000ms。
示例:

@HystrixCommand(fallbackMethod = "error", 
commandProperties = { 
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", 
value = "4000") })

3、execution.timeout.enabled
表示當超時後是否會觸發fallback方法,默認爲true

4、execution.isolation.thread.interrupteOnTimeout
表示HystrixCommand.run()在發生超時時是否應該中斷執行,默認爲true。

5、execution.isolation.thread.interruptOnCance
表示HystrixCommand.run()在發生取消時,是否應該中斷執行,默認爲false

6、execution.isolation.semaphore.maxConcurrentRequests
當隔離策略使用semaphore時,最大的兵法請求量,如果請求超過這個最大值將拒絕後續的請求,默認值爲10。

3.5.4、回退

1、fallback.isolation.semaphore.maxConcurrentRequests
設置HystrixCommand.getFallback()方法允許從調用線程進行請求的最大數量,默認10;如果達到最大併發限制,則隨後的請求將被拒絕,並拋出異常。

2、fallback.enable
開啓fallback功能,默認爲true

3.5.5、斷路器

1、circuitBreaker.enabled
設置是否將使用斷路器來跟蹤健康狀況,並且如果斷路器跳閘,則將其斷路。默認爲true。

2、circuitBreaker.requestVolumeThreshold
設置滾動窗口中將使電路跳閘的最小請求數量,默認爲20.
熔斷器在整個統計時間內是否開啓的閾值,每個熔斷器默認維護10個bucket,每秒一個bucket,每個bucket記錄成功、失敗、超時、拒絕的狀態,該閾值默認爲20次。也就是一個統計窗口時間內(10秒鐘)至少請求20次,熔斷器纔會啓動。

3、circuitBreaker.sleepWindowInMilliseconds
熔斷器默認工作時間,默認爲5秒,熔斷器中斷請求5秒後會進入半打開狀態,放部分流量過去重試,如果重試成功則會恢復正常請求。

4、circuitBreaker.errorThresholdPercentage
熔斷器錯誤百分比閾值,默認爲50%。擋在一個時間窗口內出錯率超過50%後,熔斷器會自動啓動。熔斷器啓動後會自動轉發到配置的fallbackMethod,進行降級處理。

5、circuitBreaker.forceOpen
斷路器強制開關,如果設置爲true, 則表示強制打開熔斷器,所有請求都會拒絕,默認爲false

6、circuitBreaker.forceClose
斷路器強制開關,如果設置爲true, 則表示強制關閉熔斷器,所有請求都會允許,默認false。

3.5.6、度量指標

1、metrics.rollingStats.timeInMilliseconds
設置統計滾動窗口的持續時間,以毫秒爲單位,默認10秒。

2、metrics.rollingStats.numBuckets
該屬性設置滾動統計窗口分詞的桶的數量,默認10

3、metrics.rollingPercentile.enable
表示執行延遲是否應該跟蹤和計算爲百分比。如果被禁用,則所有彙總統計返回爲-1。默認爲true。

4、metrics.rollingPercentile.timeInMilliseconds
設置滾動窗口的持續時間,在該窗口中保留執行時間以允許百分數計算(單位毫秒),默認一分鐘。

5、metrics.rollingPercentile.numBuckets
設置rollingPercentile窗口被分成的桶的數量,默認爲6

6、metrics.rollingPercentile.bucketSize
設置每個存儲桶的最大執行次數,如果在執行多次,將在桶的開頭重寫,默認100
例如,如果存儲區大小設置爲100,並表示10秒的存儲區窗口,但在此期間發生500次執行,則只有最後100次執行將保留在該10秒存儲區中。

7、metrics.healthSnapshot.intervalInMilliseconds
設置允許執行健康快照之間等待的時間(以毫秒爲單位),默認500

3.5.7、ThreadPool配置

1、coreSize
線程池核心線程數,默認10

2、MAXIMUMSIZE
設置線程池大小,默認10

3、maxQueueSize
配置線程池任務隊列的大小,默認值爲-1。當使用-1時,SynchronousQueue將被使用,即意味着其實這個隊列只是一個交換器,任務將被直接交給工作線程處理。如果工作線程不足,那任務將被拒絕;如果使用任何正整數,LinkedBlockingQueue將被使用。

4、queueSizeRejectionThreshold
表示等待隊列超過閾值後,開始拒絕線程請求,默認值爲5,如果maxQueueSize爲-1,則該屬性失效。

5、keepAliveTimeMinutes
設置活動保持時間,以分鐘爲單位,默認1分鐘

6、allowMaxinumSizeToDivergeFromCoreSize
設置maxinumSize剩下。這個值可以等於或高於coreSize,默認爲false。

四、Hystrix的工作流程

4.1、Hystrix的工作流程圖

在這裏插入圖片描述

4.2、工作流程說明

1、創建一個HystrixCommand或HystrixObservableCommand實例來想其他組件發出操作請求,通過構造方法來創建實例。
2、執行命令
3、緩存判斷:檢查緩存內是否有對應指令的結果,如果有,則將緩存結果直接以Observable對象的形式返回。
4、斷路器判斷:檢查Circuit Breaker的狀態,如果狀態爲開啓,Hystrix將不會執行對應指令,而是直接進入失敗處理狀態;如果狀態爲關閉,Hystrix會繼續執行。
5、線程池、任務隊列、信號量的檢查:確認是否有足夠資源執行操作指令。當線程池和隊列(或者信號量,當不使用線程池隔離模式的時候)資源滿的時候,hystrix將不會執行對應指令,並且會直接進入失敗的處理狀態。
6、HystrixObservableCommand.construct()和HystrixCommand.run():如果資源充足,Hystrix將會執行操作指令,調用最終都會到這兩個方法:HystrixObservableCommand.construct()或HystrixCommand.run()。如果執行指令的時間超時,執行線程會拋出TimeoutException異常。Hystrix會拋棄結果,並進入失敗處理狀態。如果指令執行成本,Hystrix會進行一系列的數據記錄,然後返回執行的結果。
7、統計斷路器的健康情況:Hystrix會根據記錄的數據來計算失敗比率,一旦失敗比率達到某一閾值,將自動開啓Circuit Breaker。
8、降級:如果在Command中實現了HystrixCommand.getFallback()或HystrixObservableCommand.resumeWithFallback()方法,Hystrix會返回對應方法的結果。如果沒有實現這些方法的話,仍然Hystrix會返回一個空的Observable對象,並且可以通過onError來終止並處理錯誤。
調用不同的方法返回不同的結果:

  • execute():將會拋出異常
  • queue():將會返回一個Future對象,如果調用它的get()方法將會拋出異常。
  • observe()和toObservable():都會返回上述的Observable對象
    9、返回成功:如果Hystrix執行成功,返回的響應取決於步驟2中調用命令。
    execute():阻塞型方法,返回單個結果(或者拋出異常)
    queue():異步方法,返回一個Future對象,可以從中取出單個結果(或者拋出異常)
    observe():返回Observable對象
    toObservable():返回Observable對象。

五、熔斷機制

5.1、雪崩效應概述

多個微服務之間調用的時候,假設微服務A調用微服務B和微服務C,微服務B和微服務C又調用了其他的微服務,這就是所謂的“扇出”。如果扇出的鏈路上,某個微服務的調用響應時間過長或不可用,對微服務A的調用就會佔用越來越多的系統資源,進而引起系統崩潰,這就是所謂的“雪崩效應”。

熔斷機制是應對雪崩效應的一種微服務鏈路保護機制。當扇出鏈路的某個微服務不可用或相應時間太長,會進行服務的降級,進而熔斷該節點微服務的調用,快速返回錯誤的響應信息。當檢測到該節點微服務調用響應正常後,恢復調用鏈路。

在Spring Cloud框架裏,熔斷機制通過Hystrix實現。Hystrix會監控微服務間調用的狀況,當失敗的調用到一定閾值,缺省是5秒內20次調用失敗,就會啓動熔斷機制。熔斷機制的註解是@HystrixCommand。

5.2、熔斷類型

在Hystrix裏,熔斷又分爲三種情況:半熔斷、熔斷打開、熔斷關閉。
1、熔斷打開:請求不再進行調用當前服務,內部設置時鐘一般爲MTTR(平均故障處理時間),當打開時長達到所設時鐘,則進入半熔斷狀態。
2、半熔斷:部分請求根據規則調用當前服務,如果請求成功,且符合規則,則認爲當前服務恢復正常,關閉熔斷。
3、熔斷關閉:熔斷關閉不會對服務進行熔斷。

5.3、斷路器原理

在這裏插入圖片描述

5.3.1、斷路器在上面情況下開始起作用

涉及到斷路器的三個重要參數:快照時間窗、請求總數閾值、錯誤百分比閾值。
1、快照時間窗:段利器確定是否打開,需要統計一些請求和錯誤數據,而統計的時間範圍就是快照時間窗,默認是最近10秒。
2、請求總數閾值:在快照時間窗內,必須滿足請求總數閾值纔有資格熔斷。默認爲20,意味着在10秒內,如果該Hystrix命令的調用次數不足20次,及時所有的請求都超時或其他原因失敗,斷路器都不會打開。
3、錯誤百分比一致:當請求綜述在快照時間窗內超過了閾值,比如發生了30次調用,如果在這30次調用中,有15次發生了超時異常,也就是超過50%的錯誤百分比,在默認設定50%閾值情況下,這時就會將斷路器打開。

5.3.2、斷路器開啓或關閉的條件

1、當滿足一定閾值的時候(默認10秒內超過20個請求次數)
2、當失敗率達到一定的時候(默認10秒內超過50%的請求失敗)
3、到達以上閾值,斷路器將會開啓
4、當開啓的時候,所有請求都不會進行轉發
5、一段時間之後(默認是5秒),這個時候斷路器是半開狀態,會讓其中一個請求進行轉發:如果成功,斷路器會關閉;若失敗,繼續開啓,重複4和5步驟。

5.3.3、斷路器打開之後

1、在用請求調用的時候,將不會調用主邏輯,而是直接調用降級fallback。通過斷路器,實現了自動地發現錯誤,並將降級邏輯切換爲主邏輯,減少響應延遲的效果。
2、原來的主邏輯要如何恢復呢?
對於這一問題,hystrix也爲我們實現了自動恢復的功能。
當斷路器打開,對主邏輯進行熔斷後,hystrix會啓動一個休眠時間窗,在這個時間窗內,降級邏輯是臨時的成爲主邏輯,當休眠時間窗到期,斷路器將進入半開狀態,釋放一次請求到原來的主邏輯上,如果此次請求正常返回,那麼斷路器將繼續閉合,主邏輯恢復,如果這次請求依然有問題,斷路器繼續進入打開狀態,休眠時間窗重新計時。

六、線程隔離機制

6.1、線程隔離示意圖

在這裏插入圖片描述
在這裏插入圖片描述

6.2、依賴隔離機制

Hystrix提供了兩種隔離策略:線程池隔離和信號量隔離,默認採用線程池隔離。

6.2.1、線程池隔離

Hystrix使用艙壁模式來實現線程池的隔離。他會爲每一個Hystrix命令創建一個獨立的線程池,不同服務通過使用不同線程池,彼此間將不受影響,這樣就算某個Hystrix命令包裝下的依賴服務出現延遲過高的情況,也只是對該依賴服務的調用產生影響,而不會拖慢其他的服務。

這種方式需要爲每個依賴的服務申請線程池,有一定的資源消耗;通過線程池大小可以控制併發量,當線程池飽和時,可以提前拒絕服務,防止依賴問題擴散。建議線程池不要設置過大,否則大量阻塞線程有可能會拖慢服務器。

6.2.1.1、線程池隔離的好處

1、應用自身得到了完全的保護,不會受不可控的依賴服務影響。
2、可以有效的降低接入新服務的風險。
3、當依賴的服務從失效恢復正常後,它的線程池會被清理,並能夠馬上恢復健康的服務,相比之下,容器級別的清理恢復速度要慢得多。
4、當依賴的服務出現配置錯誤的時候,線程池會快速的反應出此問題(通過失敗次數、延遲、超時、拒絕等指標的增減情況)。同時,可以在不影響應用功能的情況下,通過實時的動態屬性刷新來處理它。
5、當依賴的服務因失血機制調整等原因,造成其性能出現很大變化時,此時線程池的監控指標信息會反映出這樣的變化。同時,可以通過實時動態刷新自身應用對依賴服務的閾值進行調整以適應依賴方的改變。

6.2.2、信號量隔離

線程隔離會帶來線程開銷,有些成績(比如無網絡請求場景)可能會因爲用開銷換隔離得不償失,爲此hystrix提供了信號量隔離,當服務的併發數大於信號量閾值時,將進入fallback。

實現方式是使用一個原子計數器(或信號量)來記錄當前有多少個線程在允許,請求過來了,先判斷計數器的數值,若超過設置的最大線程個數,則丟棄該類型的新請求,若不超過,則執行技術操作請求來計數器+1。

信號隔離與線程隔離最大不同在於執行依賴代碼的線程依然是請求線程;而線程池方式下業務請求線程和執行依賴的服務的線程,不是同一個線程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章