SpringCloud Feign Hystrix 熔斷、線程使用坑記錄

SpringCloud Feign Hystrix 熔斷、線程使用坑記錄

坑:

  1. 併發時Feign提供的服務其中一個接口出現超時異常次數多了,導致該Feign整個服務不可用,其實是hystrix進行了熔斷處理,Hystrix參考資料
  2. Feign提供服務,併發起來10個以上,就會出現線程池拒絕異常RejectedExecutionException,也是Hystrix搞的鬼,其默認線程池是10個,關於Hystrix線程池的參考資料

參考文章中說明了幾點會出現熔斷(打開斷路器)的:一個是請求到達一定的閾值、一個是錯誤發生超過了一定的比例。

第一個問題:

是由於feign的超時出現了錯誤,當併發訪問達到一定錯誤比例的是,hystrix變開啓了斷路器(服務級別),那麼該服務下所有的接口將變得不可用。

首先我們看hystrix的超時通用配置:

hystrix:
  command:
    ## 默認全局配置
    default:
      #fallback:
        # 是否關閉回退方法
        #enable: true
        #isolation:
          #semaphore:
            ## 當觸發fallback時,併發最大出發fallback的數量,超過該數量直接拒絕服務
            #maxConcurrentRequests: 1000
      execution:
        # 斷路器
        circuitBreaker:
          #確定斷路器是否用於跟蹤運行狀況和斷路請求
          #enable: true
          #當在配置時間窗口內達到此數量的失敗後,進行短路。默認20個,如:10s內請求失敗數量達到20個,斷路器開
          requestVolumeThreshold: 20
          #短路多久以後開始嘗試是否恢復,默認5s,缺省情況採用的是連續錯誤次數來隔離,一旦一個實例訪問成功,馬上恢復實例的訪問
          sleepWindowInMilliseconds: 5000
          #出錯百分比閾值,當達到此閾值後,開始短路。默認50%,(建議業務不要使用)
          #errorThresholdPercentage: 50
          #強制打開熔斷器,如果打開這個開關,那麼拒絕所有request,默認false
          #forceOpen: false
          #強制關閉熔斷器 如果這個開關打開circuit將一直關閉且忽略circuitBreaker.errorThresholdPercentage
          #forceClosed: false
          #關閉超時熔斷功能
        #timeout:
         #enable: false
        isolation:
          # 隔離策略:有THREAD(默認)(單獨的線程上執行,併發請求受線程池中的線程數量的限制)和SEMAPHORE(調用線程上執行,併發請求受到信號量計數的限制)
          #strategy: THREAD
          #semaphore:
            #當觸發fallback時,併發最大出發fallback的數量,超過該數量直接拒絕服務,默認10,SEMAPHORE模式有效
            #maxConcurrentRequests: 10
          thread:
            #設置熔斷超時時間,默認1S,容易出現 fallback available 異常
            #在THREAD模式下,達到超時時間,可以中斷,在SEMAPHORE模式下,會等待執行完成後,再去判斷是否超時
            timeoutInMilliseconds: 5000
            #調用線程允許請求HystrixCommand.GetFallback()的最大數量,默認10
            #maxConcurrentRequests: 10
            #在發生超時時是否應中斷,默認值:true,THREAD模式有效
            #interruptOnTimeout: true
            #當發生取消時,執行是否應該中斷,默認值:true,THREAD模式有效
            #interruptOnCancel: true

這裏主要關注:hystrix.command.execution.circuitBreaker.isolation.thread.timeoutInMilliseconds這一項配置,默認值是2S,
並且這個配置的值要小於ribbon.ReadTimeout配置時間。

其次,既然是單個接口導致的服務超時,其他接口是可用的,而這裏又是全局的配置,所以Hystrix也提供了針對接口級別的配置:

hystrix:
 command:
   ## 接口級別配置,其格式:feign名稱#方法名(參數類型)
   #ProducerFeign#timeout(String):
     #execution:
       #isolation:
         #thread:
           #timeoutInMilliseconds: 5000

此外,hystrix使用Archaius來提供動態屬性修改的支持,擴展步驟:

1.初始化配置獲取源,這裏可以從配置中心、redis、zookeeper等,實現com.netflix.config.PolledConfigurationSource接口的poll方法,參考類:DynamicConfigSource

2.配置並初始化自動配置com.netflix.config.DynamicConfiguration,通過定時任務去定時刷新的,參考類:InitHystrixConfiguration

3.其他更多參考博文資料:hystrix 簡單使用以及動態配置更新zookeeper的動態配置

以上能實現接口級別的隔離配置,來解決部分處理耗時的接口超時到時服務不可用的問題。

第二個問題:

併發起來,超過個10個線程出現線程拒絕異常java.util.concurrent.RejectedExecutionException

同樣套路,我們來先看下配置:

hystrix:
  # 線程池
  threadpool:
    default:
      #默認爲10,基本得原則時保持線程池儘可能小,他主要是爲了釋放壓力,防止資源被阻塞
      coreSize: 50
      ## 最大排隊長度。默認-1,不能動態調整
      maxQueueSize: 1000
      #動態控制線程池隊列的上限,即使maxQueueSize沒有達到,達到queueSizeRejectionThreshold該值後,請求也會被拒絕,默認值5
      #queueSizeRejectionThreshold: 800

默認線程池的配置只有10,而maxQueueSize也沒有配置,queueSizeRejectionThreshold默認爲5,那麼超過10個線程併發請求即會出現線程拒絕異常了。

這裏建議是:coreSize儘可能的小,maxQueueSize是不可動態修改的,queueSizeRejectionThreshold參數可以動態調整,可以用到上述第一個問題動態修改的套路使用,
但這個值超過maxQueueSize的值就會失效

其他參考博文:踩坑 Spring Cloud Hystrix 線程池隊列配置

此外,這裏再擴展兩個優化點

  1. Hystrix請求緩存,請注意,僅針對同一線程內請求的緩存。這裏使用註解來實現,步驟:

1.實現一個filter,用來攔截所有請求的時候,初始化hystrix的上下文,參考類:HystrixCacheFilter

2.需要一個@ServletComponentScan註解來掃描到這個filter,參考類:HystrixCacheConfiguration

3.接口上使用@CacheResult註解,參考類:ProducerFeign

  1. 針對Feign服務接口做一層JVM緩存,提高短時間內重複請求的吞吐量和效率,本案例使用:springboot cache + caffeine 實現,接口上使用@Cacheable註解標記,參考類:CaffeineCacheConfiguration

Github-Demo地址

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