Hystrix使用與分析

1、資源隔離

分佈式環境中咱們不能確保調用的依賴服務不發生問題。諸如基礎設施服務器宕機(數據庫、緩存),外部依賴服務掛掉,網絡抖動引發的鏈接超時。當這些狀況發生時,大量請求迅速涌到鏈路上的故障節點,就會像繁忙的高速公路上發生交通事故短期內就會形成交通擁堵,直至癱瘓。html

不能讓局部服務的故障不斷擴散蔓延致使全局系統不可用,形成重大生產事故,因此要對外部依賴進行資源隔離,將故障控制在小範圍內。java

hystrix兩種隔離策略

線程池隔離策略(默認)

建立副線程去調用依賴服務, 執行依賴代碼的線程與請求線程(好比Tomcat線程)分離 ,當副線程請求調用失敗、超時等異常狀況而阻塞時不會影響到主線程。算法

能夠利用線程可設置超時的特性給經過網絡進行的服務間調用設置超時時間。spring

線程池機制的優缺點數據庫

線程池機制的優勢:後端

(1) 任何一個依賴服務均可以被隔離在本身的線程池內,即便本身的線程池資源填滿了,也不會影響任何其餘的服務調用;緩存

(2) 服務能夠隨時引入一個新的依賴服務,由於即便這個新的依賴服務有問題,也不會影響其餘任何服務的調用;tomcat

(3) 當一個故障的依賴服務從新變好的時候,能夠經過清理掉線程池,瞬間恢復該服務的調用,而若是是tomcat線程池被佔滿,再恢復就很麻煩;服務器

(4) 若是一個client調用配置有問題,線程池的健康情況隨時會報告,好比成功/失敗/拒絕/超時的次數統計,而後能夠近實時熱修改依賴服務的調用配置,而不用停機;網絡

(5) 若是一個服務自己發生了修改,須要從新調整配置,此時線程池的健康情況也能夠隨時發現,好比成功/失敗/拒絕/超時的次數統計,而後能夠近實時熱修改依賴服務的調用配置,而不用停機;

(6) 基於線程池的異步本質,能夠在同步的調用之上,構建一層異步調用層;

線程池機制的缺點:

(1) 線程池機制最大的缺點就是增長了cpu的開銷。

信號量隔離策略

用於隔離本地代碼,利用信號量限制同時運行的線程數量,不會建立副線程,開銷較小(複雜算法、多重循環,時間複雜度高的狀況)。

2、限流

hystrix利用線程池的工做原理來進行限流。

線程池的工做原理
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
  • corePoolSize 爲線程池的基本大小。
  • maximumPoolSize 爲線程池最大線程大小。
  • keepAliveTimeunit 則是線程空閒後的存活時間。
  • workQueue 用於存聽任務的阻塞隊列。
  • handler 當隊列和最大線程池都滿了以後的飽和策略。

188580-202ba87b6a285694.jpg

四種拒絕策略

2018110923282372.png

AbortPolicy:不處理,直接拋出異常。
CallerRunsPolicy:若線程池還沒關閉,調用當前所在線程來運行任務,r.run()執行。
DiscardOldestPolicy:LRU策略,丟棄隊列裏最近最久不使用的一個任務,並執行當前任務。
DiscardPolicy:不處理,丟棄掉,不拋出異常。

3、主要參數配置

@HystrixCommand(commandKey = "getCompanyInfoById",
                    groupKey = "company-info",
                    threadPoolKey = "company-info",
                    fallbackMethod = "fallbackMethod",
                    threadPoolProperties = {
                        @HystrixProperty(name = "coreSize", value = "30"),
                        @HystrixProperty(name = "maxQueueSize", value = "101"),
                        @HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
                        @HystrixProperty(name = "queueSizeRejectionThreshold", value = "15"),
                     })
  • commandKey: 表明一個接口, 若是不配置,默認是@HystrixCommand註解修飾的函數的函數名。
  • groupKey: 表明一個服務,一個服務可能會暴露多個接口。 Hystrix會根據組來組織和統計命令的告、儀表盤等信息。Hystrix命令默認的線程劃分也是根據命令組來實現。默認狀況下,Hystrix會讓相同組名的命令使用同一個線程池,因此咱們須要在建立Hystrix命令時爲其指定命令組來實現默認的線程池劃分。
  • threadPoolKey: 對線程池進行更細粒度的配置,默認等於groupKey的值。若是依賴服務中的某個接口耗時較長,須要單獨特殊處理,最好單獨用一個線程池,這時候就能夠配置threadpool key。也能夠多個服務接口設置同一個threadPoolKey構成線程組。
  • fallbackMethod:@HystrixCommand註解修飾的函數的回調函數,@HystrixCommand修飾的函數必須和這個回調函數定義在同一個類中,由於定義在了同一個類中,因此fackback method能夠是public/private都可。
  • 線程池配置:coreSize表示核心線程數,hystrix默認是10;maxQueueSize表示線程池的最大隊列大小; keepAliveTimeMinutes表示非核心線程空閒時最大存活時間;queueSizeRejectionThreshold:該參數用來爲隊列設置拒絕閾值。經過該參數,即便隊列沒有達到最大值也能拒絕請求。

4、降級

服務提早配置備用措施,當故障發生時無縫啓用備用方案(或者返回一些默認值),用戶無感知,最終目的都是爲了提供7*24小時穩定服務,這樣對用戶來講纔是高價值、可信賴的優質服務。

線程run()拋出異常,超時,線程池或信號量滿了,或短路了,都會觸發fallback機制。

5、熔斷

當請求調用失敗率達到閥值自動觸發降級(如因網絡故障/超時形成的失敗率高),熔斷器觸發的快速失敗會進行快速恢復。

工做流程:

  1. 若是通過斷路器的流量超過了必定的閾值,HystrixCommandProperties.circuitBreakerRequestVolumeThreshold()配置,默認20。好比,要求在10s內,通過短路器的流量必須達到20個纔會去判斷要不要短路;
  2. 若是斷路器統計到的異常調用的佔比超過了必定的閾值,HystrixCommandProperties.circuitBreakerErrorThresholdPercentage()配置。若是達到了上面的要求,好比說在10s內,通過短路器的請求達到了30個;同時其中異常的訪問數量,佔到了必定的比例(默認50%),好比60%的請求都是異常(報錯,timeout,reject),會開啓短路;
  3. 而後斷路器從close狀態轉換到open狀態;
  4. 斷路器打開的時候,全部通過該斷路器的請求所有被短路,不調用後端服務,直接走fallback降級邏輯;
  5. 通過了一段時間以後,HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds()配置,斷路器會half-open狀態,讓一條請求通過短路器,看能不能正常調用。若是調用成功了,那麼斷路器就自動恢復,轉到close狀態。

6、監控

根據監控結果能夠看出合理的超時時長配置和計算出服務集羣部署的規模大小。

u=2568138430,3468427254&fm=173&app=49&f=JPEG.jpg

計算公式:

服務集羣部署的規模大小 = 服務在健康狀態時每秒支撐的最大請求數 * 第99百分位延遲時間(以秒爲單位)+ 少許用於緩衝的額外線程

舉個例子:某個服務須要支撐的QPS爲1000,即每秒須要處理1000個請求。假設經過統計獲得百分之99的服務耗時爲100ms,那一個線程1秒內能處理10個請求,一臺機器的線程池大小通常就使用默認配置爲10,即一臺機器1秒內能處理 10 * 10 = 100個請求,最後得出該服務總共須要部署 1000/100 = 10臺機器。

7、請求緩存、合併

請求緩存

在一次請求中,若是有多個command,參數都是同樣的,調用的接口也是同樣的,其實結果能夠認爲也是同樣的。這個時候,可讓第一次command執行返回的結果,被緩存在內存中,而後在這個請求上下文中,後續的其餘對這個依賴的調用所有從內存中取用緩存結果就能夠了。

https://blog.csdn.net/zhuchua...

請求合併

高併發的場景下,將一個時間窗口內多個相同請求合併成一個請求,較少網絡鏈接次數。

http://blog.didispace.com/spr...

8、開發中遇到的問題

默認狀況下,hystrix不會將父線程的上下文傳播到有hystrix命令管理的線程中。例如,在默認狀況下,對被父線程調用並由@HystrixCommand保護的方法而言,在父線程中設置爲ThreadLocal的值是不會自動傳遞到子線程的。實際場景中的例子,調用通用UserUtil工具類從請求頭獲取不到userId, jwt串, 租戶id。

兩種方法:

(1) 手動設置

​ 手動從父線程ThreadLocal中取出須要的key-value設置到子線程中。

(2) 代碼配置

​ 自定義HystrixConcurrencyStrategy

https://www.cnblogs.com/duanx...

相關文章
相關標籤/搜索