SpringCloud組件之Hystrix組件的使用


聲明:本文根據魯班學院商鞅老師課程資料整理得來

幫助:本文涉及到的詳細代碼請參考:https://github.com/LoveWK/mySpringCloud.git

Hystrix(斷路器)是什么?

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

  “斷路器”本身是一種開關裝置,當某個服務單元發生故障之后,通過斷路器的故障監控(類似熔斷保險絲),向調用方返回一個符合預期的、可處理的備選響應(FallBack),而不是長時間的等待或者拋出調用方無法處理的異常,這樣就保證了服務調用方的線程不會被長時間、不必要地占用,從而避免了故障在分布式系統中的蔓延,乃至雪崩。

大型項目中會出現的一些問題?

  典型的一個案例就是服務血崩效應 我們來看一張圖:

  

   上圖是一條微服務調用鏈, 正常的情況我們就不必在討論了, 我們來說一下非正常情況, 假設現在 微服務H 響應時間過長,或者微服務H直接down機了如圖:

  

   來看下上圖, 我們聯想一下上圖, 如果發生這種情況, 也就是說所有發給微服務D的請求 都會被卡在微服務H那, 就會導致線程一直累計在這里, 那么其他的微服務(比如A,B,C...) 就沒有可用線程了, 導致整個服務器崩潰,這就是服務血崩。

  導致服務雪崩的情況我們來總結一下,再看看怎么解決:

    程序BUG,數據不匹配,響應時間過長,服務不可用等等.....

  針對上面的問題,我們來看看有哪些解決方案 :

    服務限流

    超時監控

    服務熔斷

    服務降級  

降級,超時:

  我們先來解釋一下降級,降級是當我們的某個微服務響應時間過長,或者不可用了,講白了也就是那個微服務調用不了了,我們不能把錯誤信息返回出來,或者讓他一直卡在那里,所以要在准備一個對應的策略(一個方法)當發生這種問題的時候我們直接調用這個方法來快速返回這個請求,不讓他一直卡在那 。

  講了這么多,我們來看看具體怎么操作:

  我們剛剛說了某個微服務調用不了了要做降級,也就是說,要在調用方做降級(不然那個微服務都down掉了再做降級也沒什么意義了) 比如說我們 user 調用power 那么就在user 做降級

  1.首先加入Hystrix的依賴

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

  

   2.在啟動類加入注解@EnableHystrix或者@EnableCircuitBreaker(他們之間是一個繼承關系,2個注解所描述的內容是完全一樣的

/** * User啟動類 */ @SpringBootApplication @EnableEurekaClient @EnableHystrix public class AppUser { public static void main(String[] args) { SpringApplication.run(AppUser.class); } }

  

   3.然后在我們的controller中對應的方法上加入注解@HystrixCommand(fallbackMethod就是我們剛剛說的降級方法的名字)

   @RequestMapping("/getHystrix.do") @HystrixCommand(fallbackMethod = "HystrixFallBackMethod") public R getHystrix(String name){ return R.success("操作成功","熔斷器方法"); }

  

   4.接下來我們寫熔斷降級后的方法,也就是@HystrixCommand(fallbackMethod = "HystrixFallBackMethod")這個注解對應的方法

    public R HystrixFallBackMethod(String name){ System.out.println("name:"+name); return R.error("熔斷降級"); }

  

   這里的這個降級信息具體內容得根據業務需求來, 比如說返回一個默認的查詢信息,亦或是系統維護(因為有可能要暫時關閉某個微服務而吧資源讓給其他服務)等等...

  5.我們在power代碼里面模擬一個異常

  

   6.啟動服務,調用程序,查看一下結果,我們發現當調用出現異常的服務時,會走熔斷方法。

    

  

   7.當我們給程序設置等待時間時,也會觸發熔斷方法。

    比如我們在power1中設置2秒的睡眠時間,也會發現觸發熔斷

    

    因為hystrix他有默認的超時監聽,當你這個請求默認超過了1秒鍾就會超時,當然這個時間時可以配置的。

降級的作用?

  第一, 他可以監聽你的請求有沒有超時。

  第二,報錯了他這里直接截斷了沒有讓請求一直卡在這里。

  其實降級還有一個好處, 就是當你的系統馬上迎來大量的並發(雙十一秒殺這種 或者促銷活動)  這時候如果發現系統馬上承載不了這么大的並發時, 可以考慮先關閉一些不重要的微服務(在降級方法里面返回一個比較友好的信息),把資源讓給主微服務。

  總結一下就是,整體資源快不夠了,忍痛將某些服務先關掉,待渡過難關,再開啟回來。

熔斷,限流:

  講完降級,我們來講講熔斷,其實熔斷,就好像我們生活中的跳閘一樣, 比如說你的電路出故障了,為了防止出現大型事故 這里直接切斷了你的電源以免意外繼續發生, 把這個概念放在我們程序上也是如此, 當一個微服務調用多次出現問題時(默認是10秒內20次當然 這個也能配置),hystrix就會采取熔斷機制,不再繼續調用你的方法(會在默認5秒鍾內和電器短路一樣,5秒鍾后會試探性的先關閉熔斷機制,但是如果這時候再失敗一次{之前是20次} 那么又會重新進行熔斷) 而是直接調用降級方法,這樣就一定程度上避免了服務雪崩的問題

  限流:

    限流, 顧名思義, 就是限制你某個微服務的使用量(可用線程)

    hystrix通過線程池的方式來管理你的微服務調用,他默認是一個線程池(10大小) 管理你的所有微服務,你可以給某個微服務開辟新的線程池:

@RequestMapping("/feignOrder.do") @HystrixCommand(fallbackMethod = "fallbackOrderMethod" , threadPoolKey = "order", threadPoolProperties ={@HystrixProperty(name = "coreSize",value = "2") ,@HystrixProperty(name = "maxQueueSize",value = "1"}) public Object feignOrder(String name){ System.out.println(1); return restTemplate.getForObject(ORDERURL+"/order.do",Object.class); }

  threadPoolKey 就是在線程池唯一標識, hystrix 會拿你這個標識去計數,看線程占用是否超過了, 超過了就會直接降級該次調用

   比如, 這里coreSize給他值為2 那么假設你這個方法調用時間是3s執行完, 那么在3s內如果有超過2個請求進來的話, 剩下的請求則全部降級

 feign整合Hystrix:

  feign 默認是支持hystrix的, 但是在Spring - cloud Dalston 版本之后就默認關閉了, 因為不一定業務需求要用的到,所以現在要使用首先得打開他,在yml文件加上如下配置: 

feign:
hystrix:
enabled: true

  

  加上配置之后降級方法怎么寫呢?

  首先在在feign客戶端的注解上 有個屬性叫fallback 然后指向一個類

/** * feign客戶端 */ @FeignClient(name = "SERVER-POWER",fallback = PowerFeignClientFallBack.class) public interface PowerFeignClient { @RequestMapping("/getPower.do") public Object getPower(); }

  

   編寫降級類,並使用注解@Component將其注入到容器中去

/** * feign的熔斷類 */ @Component public class PowerFeignClientFallBack implements PowerFeignClient { @Override public Object getPower() { return R.error("測試降級"); } }

  這樣子,方法降級就寫好了

  當然 可能你有這種需求, 需要拿到具體的錯誤信息, 那么可以這樣寫一個類實現FallbackFactory<>接口,泛型就穿你的接口類。

/** * 熔斷類 */
public class PowerFeignClientFallBackFactory implements FallbackFactory<PowerFeignClient> { @Override public PowerFeignClient create(Throwable throwable) { return new PowerFeignClient() { @Override public Object getPower() { //得到具體錯誤信息
                String message = throwable.getMessage(); return R.error("測試降級"); } }; } }

  然后在客戶端指定一個fallbackFactory就好了

/** * feign客戶端 */
//@FeignClient(name = "SERVER-POWER",fallback = PowerFeignClientFallBack.class)
@FeignClient(name = "SERVER-POWER",fallbackFactory = PowerFeignClientFallBackFactory.class) public interface PowerFeignClient { @RequestMapping("/getPower.do") public Object getPower(); }

  至此, 就完成了feign與hystrix的整合

Hystrix相關配置:

  Execution相關的屬性的配置

  hystrix.command.default.execution.isolation.strategy 隔離策略,默認是Thread, 可選Thread| Semaphor

  hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 命令執行超時時 間,默認1000ms

  hystrix.command.default.execution.timeout.enabled 執行是否啟用超時,默認啟用true

  hystrix.command.default.execution.isolation.thread.interruptOnTimeout 發生超時是是否中斷, 默認true

  hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests 最大並發請求 數,默認10,該參數當使用ExecutionIsolationStrategy.SEMAPHORE策略時才有效。如果達到最大並發請求 數,請求會被拒絕。理論上選擇semaphore size的原則和選擇thread size一致,但選用semaphore時每次執行 的單元要比較小且執行速度快(ms級別),否則的話應該用thread。 semaphore應該占整個容器(tomcat)的線程池的一小部分。 Fallback相關的屬性 這些參數可以應用於Hystrix的THREAD和SEMAPHORE策略

  hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests 如果並發數達到 該設置值,請求會被拒絕和拋出異常並且fallback不會被調用。默認10

  hystrix.command.default.fallback.enabled 當執行失敗或者請求被拒絕,是否會嘗試調用

  hystrixCommand.getFallback() 。默認true

  Circuit Breaker相關的屬性
  hystrix.command.default.circuitBreaker.enabled 用來跟蹤circuit的健康性,如果未達標則讓request短路。默認true


  hystrix.command.default.circuitBreaker.requestVolumeThreshold 一個rolling window內最小的請 求數。如果設為20,那么當一個rolling window的時間內(比如說1個rolling window是10秒)收到19個請求, 即使19個請求都失敗,也不會觸發circuit break。默認20


  hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds 觸發短路的時間值,當該值設 為5000時,則當觸發circuit break后的5000毫秒內都會拒絕request,也就是5000毫秒后才會關閉circuit。 默認5000


  hystrix.command.default.circuitBreaker.errorThresholdPercentage錯誤比率閥值,如果錯誤率>=該 值,circuit會被打開,並短路所有請求觸發fallback。默認50


  hystrix.command.default.circuitBreaker.forceOpen 強制打開熔斷器,如果打開這個開關,那么拒絕所 有request,默認false


  hystrix.command.default.circuitBreaker.forceClosed 強制關閉熔斷器 如果這個開關打開,circuit將 一直關閉且忽略circuitBreaker.errorThresholdPercentage

  Metrics相關參數

  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被划分的數 量,若numBuckets=10,rolling window=10000,那么一個bucket的時間即1秒。必須符合rolling window  % numberBuckets == 0。默認10

  hystrix.command.default.metrics.rollingPercentile.enabled 執行時是否enable指標的計算和跟蹤, 默認true

  hystrix.command.default.metrics.rollingPercentile.timeInMilliseconds 設置rolling  percentile window的時間,默認60000

  hystrix.command.default.metrics.rollingPercentile.numBuckets 設置rolling percentile  window的numberBuckets。邏輯同上。默認6

  hystrix.command.default.metrics.rollingPercentile.bucketSize 如果bucket size=100,window =10s,若這10s里有500次執行,只有最后100次執行會被統計到bucket里去。增加該值會增加內存開銷以及排序 的開銷。默認100

  hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds 記錄health 快照(用 來統計成功和錯誤綠)的間隔,默認500ms


  Request Context 相關參數

  hystrix.command.default.requestCache.enabled 默認true,需要重載getCacheKey(),返回null時不 緩存

   hystrix.command.default.requestLog.enabled 記錄日志到HystrixRequestLog,默認true
 
   Collapser Properties 相關參數
 
   hystrix.collapser.default.maxRequestsInBatch 單次批處理的最大請求數,達到該數量觸發批處理,默認 Integer.MAX_VALU
 
   hystrix.collapser.default.timerDelayInMilliseconds 觸發批處理的延遲,也可以為創建批處理的時間 +該值,默認10
 
   hystrix.collapser.default.requestCache.enabled 是否對HystrixCollapser.execute() and  HystrixCollapser.queue()的cache,默認true
 
   ThreadPool 相關參數
 
   線程數默認值10適用於大部分情況(有時可以設置得更小),如果需要設置得更大,那有個基本得公式可以 follow: requests per second at peak when healthy × 99th percentile latency in seconds + some  breathing room 每秒最大支撐的請求數 (99%平均響應時間 + 緩存值) 比如:每秒能處理1000個請求,99%的請求響應時間是60ms,那么公式是: 1000 (0.060+0.012)
 
   基本得原則時保持線程池盡可能小,他主要是為了釋放壓力,防止資源被阻塞。 當一切都是正常的時候,線程池一般僅會有1到2個線程激活來提供服務
 
   hystrix.threadpool.default.coreSize 並發執行的最大線程數,默認10
 
   hystrix.threadpool.default.maxQueueSize BlockingQueue的最大隊列數,當設為-1,會使用
 
   SynchronousQueue,值為正時使用LinkedBlcokingQueue。該設置只會在初始化時有效,之后不能修改threadpool的queue size,除非reinitialising thread executor。默認-1。
 
   hystrix.threadpool.default.queueSizeRejectionThreshold 即使maxQueueSize沒有達到,達到 queueSizeRejectionThreshold該值后,請求也會被拒絕。因為maxQueueSize不能被動態修改,這個參數將允 許我們動態設置該值。if maxQueueSize == 1,該字段將不起作用   

  hystrix.threadpool.default.keepAliveTimeMinutes 如果corePoolSize和maxPoolSize設成一樣(默認 實現)該設置無效。如果通過plugin(https://github.com/Netflix/Hystrix/wiki/Plugins)使用自定義 實現,該設置才有用,默認1.


   hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds 線程池統計指標的時間,默 認10000
 
   hystrix.threadpool.default.metrics.rollingStats.numBuckets 將rolling window划分為n個 buckets,默認10


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM