Hystrix是什麼?
Hystrix 能使你的系統在出現依賴服務失效的時候,通過隔離系統所依賴的服務,防止服務級聯失敗,同時提供失敗回退機制,更優雅地應對失效,并使你的系統能更快地從異常中恢複。
Hystrix能做什麼?
在通過第三方用戶端通路(通常是通過網絡)依賴服務出現高延遲或者失敗時,為系統提供保護和控制
在分布式系統中防止級聯失敗
快速失敗(Fail fast)同時能快速恢複
提供失敗回退(Fallback)和優雅的服務降級機制
提供近實時的監控、報警和運維控制手段
Hystrix設計原則?
防止單個依賴耗盡容器(例如 Tomcat)内所有使用者線程
降低系統負載,對無法及時處理的請求快速失敗(fail fast)而不是排隊
提供失敗回退,以在必要時讓失效對使用者透明化
使用隔離機制(例如『艙壁』/『泳道』模式,熔斷器模式等)降低依賴服務對整個系統的影響
針對系統服務的度量、監控和報警,提供優化以滿足近實時性的要求
在 Hystrix 絕大部分需要動态調整配置并快速部署到所有應用方面,提供優化以滿足快速恢複的要求
能保護應用不受依賴服務的整個執行過程中失敗的影響,而不僅僅是網絡請求
Hystrix實作原理-指令模式
将所有請求外部系統(或者叫依賴服務)的邏輯封裝到 HystrixCommand或者HystrixObservableCommand(依賴RxJava)對象中
Run()方法為要實作的業務邏輯,這些邏輯将會在獨立的線程中被執行當請求依賴服務時出現拒絕服務、逾時或者短路(多個依賴服務順序請求,前面的依賴服務請求失敗,則後面的請求不會發出)時,執行該依賴服務的失敗回退邏輯(Fallback)
Hystrix實作原理-艙壁模式
貨船為了進行防止漏水和火災的擴散,會将貨倉分隔為多個,當發生災害時,将所在貨倉進行隔離就可以降低整艘船的風險。
Hystrix實作原理-隔離政策
應用在複雜的分布式結構中,可能會依賴許多其他的服務,并且這些服務都不可避免地有失效的可能。如果一個應用沒有與依賴服務的失效隔離開來,那麼它将有可能因為依賴服務的失效而失效。
Hystrix将貨倉模式運用到了服務調用者上。為每一個依賴服務維護一個線程池(或者信号量),當線程池占滿,該依賴服務将會立即拒絕服務而不是排隊等待。
每個依賴服務都被隔離開來,Hystrix 會嚴格控制其對資源的占用,并在任何失效發生時,執行失敗回退邏輯。
Hystrix實作原理-觀察者模式
Hystrix通過觀察者模式對服務進行狀态監聽。
每個任務都包含有一個對應的Metrics,所有Metrics都由一個ConcurrentHashMap來進行維護,Key是CommandKey.name()
在任務的不同階段會往Metrics中寫入不同的資訊,Metrics會對統計到的曆史資訊進行統計彙總,供熔斷器以及Dashboard監控時使用。
Metrics
Metrics内部又包含了許多内部用來管理各種狀态的類,所有的狀态都是由這些類管理的
各種狀态的内部也是用ConcurrentHashMap來進行維護的
如:HealthCountsStream是用來統計任務失敗率的一個類
而每個狀态管理類内部又包含了各自的真實轉态資訊
如HealthCountsStream儲存的資訊的一部分如下:
Metrics如何統計
Metrics在統計各種狀态時,時運用滑動視窗思想進行統計的,在一個滑動視窗時間中又劃分了若幹個Bucket(滑動視窗時間與Bucket成整數倍關系),滑動視窗的移動是以Bucket為機關進行滑動的。
如:HealthCounts 記錄的是一個Buckets的監控狀态,Buckets為一個滑動視窗的一小部分,如果一個滑動視窗時間為 t ,Bucket數量為 n,那麼每t/n秒将建立一個HealthCounts對象。
Hystrix實作原理-熔斷機制
熔斷是參考電路而産生的一種保護性機制,即系統中如果存在某個服務失敗率過高時,将開啟熔斷器,對于後續的調用,不在繼續請求服務,而是進行Fallback操作。
熔斷所依靠的資料即是Metrics中的HealthCount所統計的錯誤率。
一個指令的調用過程如圖所示:
熔斷器的判斷流程:
1.一個指令執行前會先運作allowRequest()函數。
allowRequest()函數内部為:
先檢視熔斷器是否強制開啟(ForceOpen()),如果開啟則拒絕
再檢視熔斷器是否強制關閉(ForceClosed()),如果強制關閉則允許Request,否則進一步判斷
先做isOpen(),判斷熔斷器是否開啟,如果開啟則拒絕通路,如果開啟則進一步判斷
再做allowSingleTest(),熔斷器休眠期過後,允許且隻允許一個請求,如果這個請求正确執行,則熔斷器關閉,如果執行失敗,則熔斷器再次開啟,進入新的熔斷周期。
如何判斷逾時
在運作對應的command時,Hystrix會注冊一個Timer到一個定時線程池中,當逾時後會啟用一個HystrixTimer線程來終止的執行。
線程池的管理是用ThreadPoolExecutor來實作的,當線程池和阻塞隊列都滿後會抛出RejectedExecutionException,捕獲該異常并進行相應狀态的處理。
Note:除此之外由程式錯誤導緻的異常,斷路器打開都可以導緻任務失敗進入Fallback
失敗降級
Hystrix提供了失敗降級政策,當指令執行失敗時,Hystrix 将會執行失敗回退邏輯。失敗回退邏輯包含了通用的回應資訊,這些回應從記憶體緩存中或者其他固定邏輯中得到,而不應有任何的網絡依賴。
如果一定要在失敗回退邏輯中包含網絡請求,必須将這些網絡請求包裝在另一個 HystrixCommand 或 HystrixObservableCommand 中。
失敗降級也有頻率限時,如果同一fallback短時間請求過大,則會抛出拒絕異常。
緩存機制
除了第一次請求需要真正通路依賴服務以外,後續請求全部從緩存中擷取,可以保證在同一個使用者請求内,不會出現依賴服務傳回不同的回應的情況,且避免了不必要的線程執行。
緩存在指令内部,且有一個ConcurrentHashMap進行管理
使用緩存需要重寫父類的getCacheKey方法
配置
Note:視窗時間必須為桶數量的整數倍,否則會抛出異常
Dashboard
1.Hystrix 自帶了一個dashboard,用來監控熔斷資訊.
2.Dashboard可以監測哪些資料?
3.使用turbine可以監控叢集.
使用Turbine聚合的伺服器叢集
遇到問題
壓測過不了,提高阻塞隊列和線程池無效,增加fallback容量解決。
fallback.isolation.semaphore.maxConcurrentRequests = 100
Hystrix配置簡單說明
Hystrix屬性的4中優先級
1. 内置全局預設值(Global default from code)
如果下面3種都沒有設定,預設是使用此種,後面用“預設值”代指這種。
2. 動态全局預設屬性(Dynamic global default property)
可以通過屬性配置來更改全局預設值,後面用“預設屬性”代指這種。
3. 内置執行個體預設值(Instance default from code)
在代碼中,設定的屬性值,後面用“執行個體預設”來代指這種。
4. 動态配置執行個體屬性(Dynamic instance property)
可以針對特定的執行個體,動态配置屬性值,來代替前面三種,後面用“執行個體屬性”來代指這種。
優先級:1 < 2 < 3 < 4
指令屬性
執行
execution.isolation.strategy
設定HystrixCommand.run()的隔離政策,有兩種選項:
THREAD —— 在固定大小線程池中,以單獨線程執行,并發請求數受限于線程池大小。
SEMAPHORE —— 在調用線程中執行,通過信号量來限制并發量。
預設值:THREAD(ExecutionIsolationStrategy.THREAD)
可選值:THREAD,SEMAPHORE
預設屬性:hystrix.command.default.execution.isolation.strategy
執行個體屬性:
hystrix.command.HystrixCommandKey.execution.isolation.strategy
執行個體預設的設定:
// to use thread isolation
HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)
// to use semaphore isolation
.withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)
execution.isolation.thread.timeoutInMilliseconds
設定調用者等待指令執行的逾時限制,超過此時間,HystrixCommand被标記為TIMEOUT,并執行回退邏輯。
注意:逾時會作用在HystrixCommand.queue(),即使調用者沒有調用get()去獲得Future對象。
預設值:1000(毫秒)
預設屬性:hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
執行個體屬性:hystrix.command.HystrixCommandKey.execution.isolation.thread.timeoutInMilliseconds
執行個體預設的設定:HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(int value)
execution.timeout.enabled
設定HystrixCommand.run()的執行是否有逾時限制。
預設值:true
預設屬性:hystrix.command.default.execution.timeout.enabled
執行個體屬性:hystrix.command.HystrixCommandKey.execution.timeout.enabled
.withExecutionTimeoutEnabled(boolean value)
execution.isolation.thread.interruptOnTimeout
設定HystrixCommand.run()的執行是否在逾時發生時被中斷。
預設屬性:hystrix.command.default.execution.isolation.thread.interruptOnTimeout
執行個體屬性:hystrix.command.HystrixCommandKey.execution.isolation.thread.interruptOnTimeout
.withExecutionIsolationThreadInterruptOnTimeout(boolean value)
execution.isolation.thread.interruptOnCancel
設定HystrixCommand.run()的執行但取消動作發生時候可以響應中斷。
預設值:false
預設屬性:hystrix.command.default.execution.isolation.thread.interruptOnCancel
執行個體屬性:hystrix.command.HystrixCommandKey.execution.isolation.thread.interruptOnCancel
.withExecutionIsolationThreadInterruptOnCancel(boolean value)
execution.isolation.semaphore.maxConcurrentRequests
設定當使用ExecutionIsolationStrategy.SEMAPHORE時,HystrixCommand.run()方法允許的最大請求數。如果達到最大并發數時,後續請求會被拒絕。
信号量應該是容器(比如Tomcat)線程池一小部分,不能等于或者略小于容器線程池大小,否則起不到保護作用。
預設值:10
預設屬性:hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests
執行個體屬性:hystrix.command.HystrixCommandKey.execution.isolation.semaphore.maxConcurrentRequests
.withExecutionIsolationSemaphoreMaxConcurrentRequests(int value)
回退
下面的屬性控制HystrixCommand.getFallback()執行。這些屬性對ExecutionIsolationStrategy.THREAD和ExecutionIsolationStrategy.SEMAPHORE都有效。
fallback.isolation.semaphore.maxConcurrentRequests
設定調用線程産生的HystrixCommand.getFallback()方法的允許最大請求數目。
如果達到最大并發數目,後續請求将會被拒絕,如果沒有實作回退,則抛出異常。
預設屬性:hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests
執行個體屬性:hystrix.command.HystrixCommandKey.fallback.isolation.semaphore.maxConcurrentRequests
執行個體預設:
.withFallbackIsolationSemaphoreMaxConcurrentRequests(int value)
fallback.enabled
該屬性決定當故障或者拒絕發生時,一個調用将會去嘗試HystrixCommand.getFallback()。
預設屬性:hystrix.command.default.fallback.enabled
執行個體屬性:hystrix.command.HystrixCommandKey.fallback.enabled
.withFallbackEnabled(boolean value)
斷路器(Circuit Breaker)
circuitBreaker.enabled
設定斷路器是否起作用。
預設屬性:hystrix.command.default.circuitBreaker.enabled
執行個體屬性:hystrix.command.HystrixCommandKey.circuitBreaker.enabled
.withCircuitBreakerEnabled(boolean value)
circuitBreaker.requestVolumeThreshold
設定在一個滾動視窗中,打開斷路器的最少請求數。
比如:如果值是20,在一個視窗内(比如10秒),收到19個請求,即使這19個請求都失敗了,斷路器也不會打開。
預設值:20
預設屬性:hystrix.command.default.circuitBreaker.requestVolumeThreshold
執行個體屬性:hystrix.command.HystrixCommandKey.circuitBreaker.requestVolumeThreshold
.withCircuitBreakerRequestVolumeThreshold(int value)
circuitBreaker.sleepWindowInMilliseconds
設定在回路被打開,拒絕請求到再次嘗試請求并決定回路是否繼續打開的時間。
預設值:5000(毫秒)
預設屬性:hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds
執行個體屬性:hystrix.command.HystrixCommandKey.circuitBreaker.sleepWindowInMilliseconds
.withCircuitBreakerSleepWindowInMilliseconds(int value)
circuitBreaker.errorThresholdPercentage
設定打開回路并啟動回退邏輯的錯誤比率。
預設值:50
預設屬性:hystrix.command.default.circuitBreaker.errorThresholdPercentage
執行個體屬性:hystrix.command.HystrixCommandKey.circuitBreaker.errorThresholdPercentage
.withCircuitBreakerErrorThresholdPercentage(int value)
circuitBreaker.forceOpen
如果該屬性設定為true,強制斷路器進入打開狀态,将會拒絕所有的請求。
該屬性優先級比circuitBreaker.forceClosed高。
預設屬性:hystrix.command.default.circuitBreaker.forceOpen
執行個體屬性:hystrix.command.HystrixCommandKey.circuitBreaker.forceOpen
.withCircuitBreakerForceOpen(boolean value)
circuitBreaker.forceClosed
如果該屬性設定為true,強制斷路器進入關閉狀态,将會允許所有的請求,無視錯誤率。
預設屬性:hystrix.command.default.circuitBreaker.forceClosed
執行個體屬性:hystrix.command.HystrixCommandKey.circuitBreaker.forceClosed
.withCircuitBreakerForceClosed(boolean value)
請求上下文
requestCache.enabled
設定HystrixCommand.getCacheKey()是否啟用,由HystrixRequestCache通過請求緩存提供去重複資料功能。
預設屬性:hystrix.command.default.requestCache.enabled
執行個體屬性:hystrix.command.HystrixCommandKey.requestCache.enabled
.withRequestCacheEnabled(boolean value)
requestLog.enabled
設定HystrixCommand執行和事件是否要記錄日志到HystrixRequestLog。
預設屬性:hystrix.command.default.requestLog.enabled
執行個體屬性:hystrix.command.HystrixCommandKey.requestLog.enabled
.withRequestLogEnabled(boolean value)
壓縮器屬性
下面的屬性可以控制HystrixCollapser行為。
maxRequestsInBatch
設定觸發批處理執行之前,在批進行中允許的最大請求數。
預設值:Integer.MAX_VALUE
預設屬性:hystrix.collapser.default.maxRequestsInBatch
執行個體屬性:hystrix.collapser.HystrixCollapserKey.maxRequestsInBatch
執行個體預設的設定:HystrixCollapserProperties.Setter()
.withMaxRequestsInBatch(int value)
timerDelayInMilliseconds
設定批處理建立到執行之間的毫秒數。
預設屬性:hystrix.collapser.default.timerDelayInMilliseconds
執行個體屬性:hystrix.collapser.HystrixCollapserKey.timerDelayInMilliseconds
.withTimerDelayInMilliseconds(int value)
設定請求緩存是否對HystrixCollapser.execute()和HystrixCollapser.queue()的調用起作用。
預設屬性:hystrix.collapser.default.requestCache.enabled
執行個體屬性:hystrix.collapser.HystrixCollapserKey.requestCache.enabled
線程池屬性
coreSize
設定核心線程池大小。
預設屬性:hystrix.threadpool.default.coreSize
執行個體屬性:hystrix.threadpool.HystrixThreadPoolKey.coreSize
執行個體預設的設定:HystrixThreadPoolProperties.Setter()
.withCoreSize(int value)
maximumSize
1.5.9新增屬性,設定線程池最大值。這個是在不開始拒絕HystrixCommand的情況下支援的最大并發數。這個屬性起作用的前提是設定了allowMaximumSizeToDrivergeFromCoreSize。1.5.9之前,核心線程池大小和最大線程池大小總是相同的。
maxQueueSize
設定BlockingQueue最大的隊列值。
如果設定為-1,那麼使用SynchronousQueue,否則正數将會使用LinkedBlockingQueue。
如果需要去除這些限制,允許隊列動态變化,可以參考queueSizeRejectionThreshold屬性。
修改SynchronousQueue和LinkedBlockingQueue需要重新開機。
預設值:-1
預設屬性:hystrix.threadpool.default.maxQueueSize
執行個體屬性:hystrix.threadpool.HystrixThreadPoolKey.maxQueueSize
.withMaxQueueSize(int value)
queueSizeRejectionThreshold
設定隊列拒絕的門檻值——一個人為設定的拒絕通路的最大隊列值,即使maxQueueSize還沒有達到。
當将一個線程放入隊列等待執行時,HystrixCommand使用該屬性。
注意:如果maxQueueSize設定為-1,該屬性不可用。
預設值:5
預設屬性:hystrix.threadpool.default.queueSizeRejectionThreshold
執行個體屬性:hystrix.threadpool.HystrixThreadPoolKey.queueSizeRejectionThreshold
.withQueueSizeRejectionThreshold(int value)
keepAliveTimeMinutes
設定存活時間,機關分鐘。如果coreSize小于maximumSize,那麼該屬性控制一個線程從實用完成到被釋放的時間。
預設值:1
預設屬性:hystrix.threadpool.default.keepAliveTimeMinutes
執行個體屬性:hystrix.threadpool.HystrixThreadPoolKey.keepAliveTimeMinutes
.withKeepAliveTimeMinutes(int value)
allowMaximumSizeToDivergeFromCoreSize
在1.5.9中新增的屬性。該屬性允許maximumSize起作用。屬性值可以等于或者大于coreSize值,設定coreSize小于maximumSize的線程池能夠支援maximumSize的并發數,但是會将不活躍的線程傳回到系統中去。(詳見KeepAliveTimeMinutes)
預設屬性:hystrix.threadpool.default.allowMaximumSizeToDivergeFromCoreSize
執行個體屬性:hystrix.threadpool.HystrixThreadPoolKey.allowMaximumSizeToDivergeFromCoreSize
.withAllowMaximumSizeToDivergeFromCoreSize(boolean value)
metrics.rollingStats.timeInMilliseconds
設定統計的滾動視窗的時間段大小。該屬性是線程池保持名額時間長短。
預設值:10000(毫秒)
預設屬性:hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds
執行個體屬性:hystrix.threadpool.HystrixThreadPoolKey.metrics.rollingStats.timeInMilliseconds
.withMetricsRollingStatisticalWindowInMilliseconds(int value)
metrics.rollingStats.numBuckets
設定滾動的統計視窗被分成的桶(bucket)的數目。
注意:”metrics.rollingStats.timeInMilliseconds % metrics.rollingStats.numBuckets == 0"必須為true,否則會抛出異常。
可能的值:任何能被metrics.rollingStats.timeInMilliseconds整除的值。
預設屬性:hystrix.threadpool.default.metrics.rollingStats.numBuckets
執行個體屬性:hystrix.threadpool.HystrixThreadPoolProperties.metrics.rollingStats.numBuckets
.withMetricsRollingStatisticalWindowBuckets(int value)
<col>
參數
作用
備注
失敗率達到多少百分比後熔斷
主要根據依賴重要性進行調整
是否強制關閉熔斷
如果是強依賴,應該設定為true
熔斷觸發的最小個數/10s
熔斷多少秒後去嘗試請求
預設值:5000
commandKey
預設值:目前執行方法名
線程池coreSize
信号量最大并發度
SEMAPHORE模式有效,預設值:10
隔離政策,有THREAD和SEMAPHORE
預設使用THREAD模式,以下幾種可以使用SEMAPHORE模式:
隻想控制并發度
外部的方法已經做了線程隔離
調用的是本地方法或者可靠度非常高、耗時特别小的方法(如medis)
是否打開逾時線程中斷
THREAD模式有效
逾時時間
預設值:1000
在THREAD模式下,達到逾時時間,可以中斷
在SEMAPHORE模式下,會等待執行完成後,再去判斷是否逾時
是否打開逾時
fallback最大并發度
groupKey
表示所屬的group,一個group共用線程池
預設值:getClass().getSimpleName();
請求等待隊列
如果使用正數,隊列将從SynchronizeQueue改為LinkedBlockingQueue
hystrix.command.default.metrics.rollingStats.timeInMilliseconds
設定統計的時間視窗值的,毫秒值
circuit break 的打開會根據1個rolling window的統計來計算。若rolling window被設為10000毫秒,則rolling window會被分成n個buckets,每個bucket包含success,failure,timeout,rejection的次數的統計資訊。預設10000
hystrix.command.default.metrics.rollingStats.numBuckets
設定一個rolling window被劃分的數量
hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds
記錄health 快照(用來統計成功和錯誤綠)的間隔,預設500ms
熔斷器:Circuit Breaker
前一節我們了解了Hystrix利用線程池實作了對服務的隔離。
熔斷器是位于線程池之前的元件。
使用者請求某一服務之後,Hystrix會先經過熔斷器,此時如果熔斷器的狀态是打開(跳起),則說明已經熔斷,這時将直接進行降級處理,不會繼續将請求發到線程池。
套用銀行櫃員的例子,櫃員相當于服務,視窗前排隊的是線程池,大堂經理則可以看成是熔斷器。通常的流程是:客戶進門,告訴大堂經理要辦什麼業務,這時他會判斷客戶請求的視窗是否在正常處理業務,如果正常,他就會讓客戶到該視窗排隊(也就是進入了線程池),如果不正常,他根本不會讓客戶去排隊。
熔斷器相當于線上程池之前的一層屏障。
下面來看一下熔斷器的工作原理
每個熔斷器預設維護10個bucket
每秒建立一個bucket
每個blucket記錄成功,失敗,逾時,拒絕的次數
當有新的bucket被建立時,最舊的bucket會被抛棄
熔斷算法
判斷是否進行熔斷的依據是:
根據bucket中記錄的次數,計算錯誤率。
當錯誤率超過預設的值(預設是50%)且10秒内超過20個請求,則開啟熔斷。
熔斷恢複
對于被熔斷的請求,并不是永久被切斷,而是被暫停一段時間(預設是5s)之後,允許部分請求通過,若請求都是健康的(RT<250ms)則對請求健康恢複(取消熔斷),如果不是健康的,則繼續熔斷。
服務調用的各種結果(成功,異常,逾時,拒絕),都會上報給熔斷器,計入bucket參與計算。