背景,網上看到很多關於hystrix的配置都是沒生效的,如:
一.先看測試環境搭建:
order 服務通過feign 的方式調用了product 服務的getProductInfo 接口
//------------ order 服務的調用接口--------------- @FeignClient(name ="product",fallback =ProductHystrix.class) @Primary public interface ProductService { @RequestMapping("/info/{id}") Product getProductInfo(@PathVariable("id") Integer id); } @Component public class ProductHystrix implements ProductService{ @Override public Product getProductInfo(Integer id) { System.out.println("被熔斷;了"); Product product = new Product(); product.setName("熔斷了。。。。。"); return product; } } // product 服務提供的接口------------------ @Controller public class ProductController { @RequestMapping("/info/{id}") @ResponseBody @MyLogAnnotation public Product getProductInfo(@PathVariable("id") Integer id){ Product product = new Product(); product.setId(id); product.setName("蘋果手機"); return product; } }
order 服務的application.yml 開啟feign:hystrix:enabled: true
二. Hystrix 的超時時間怎么設置:
直接上代碼:hystrix 任何相關配置都可以在下面的配置類配置,我這里修改了核心線程數和最大隊列數已經超時時間
package com.yang.xiao.hui.order.controller; import com.netflix.hystrix.*; import feign.Feign; import feign.Target; import feign.hystrix.HystrixFeign; import feign.hystrix.SetterFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import java.lang.reflect.Method; @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class }) public class FeignConfig { @Bean @Scope("prototype") @ConditionalOnProperty(name = "feign.hystrix.enabled") public Feign.Builder feignHystrixBuilder() { HystrixFeign.Builder builder = HystrixFeign.builder(); SetterFactory setterFactory= new SetterFactory(){ @Override public HystrixCommand.Setter create(Target<?> target, Method method) { String groupKey = target.name(); String commandKey = Feign.configKey(target.type(), method); //HystrixThreadPoolProperties 線程池相關配置 HystrixThreadPoolProperties.Setter setter = HystrixThreadPoolProperties.Setter().withCoreSize(100).withMaxQueueSize(200); //HystrixCommandProperties 熔斷器相關屬性配置 HystrixCommandProperties.Setter setter1 = HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(6000); return HystrixCommand.Setter .withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey)) .andCommandKey(HystrixCommandKey.Factory.asKey(commandKey)) .andThreadPoolPropertiesDefaults(setter) .andCommandPropertiesDefaults(setter1); } }; builder.setterFactory(setterFactory); return builder; } }
啟動服務:通過瀏覽器輸入http://localhost:8674/info/3 調用order 服務
跟進去看HystrixCommand的創建:
由此可見線程池和熔斷超時時間都已經改變了,證明我們的配置生效了
原理分析:
在FeignClientsConfiguration這個配置類中有一段代碼:
然后跟進看到默認的對象:
HystrixCommandProperties對象有個默認的超時時間,默認是1s:
那么,我們根據上面的分析,當容器中存在HystrixFeign.builder就不會再創建該bean 了,所以我們可以自己創建一個HystrixFeign.builder 然后調用setterFactory(SetterFactory setterFactory)來修改默認的配置,也就是上面我們自己定義的配置類
熔斷器的熔斷時間是從調用下面的方法開始計算的:
三.feign超時時間怎么設置?
我們繼續跟進剛才的調用方法:
在這里默認連接時間是10s,讀取時間是60s,那么這個類是怎么創建的呢?
從上面可以知道,Options對象默認已經有個時間配置了,然而我們繼續跟蹤代碼:
我們看這里:
Options對象經過getClientConfig(options, clientName) 方法,就從10s的連接時間變成了1s,60s的讀取時間也變成了1s,上面源碼分析可以知道:
如果我們配置了feign的超時時間,那么就會以我們配置的時間為准,如果沒有配置,那么就取ribbon的超時時間,2者只能有一個生效,而ribbon默認超時時間是1秒
繼續跟進:
上述代碼可見,feign或者ribbon所配置的超時時間,最終都是在HttpUrlConnection中生效
那么,我們如何修改feign的配置時間呢?
我們回到這里:
這里說了,如果容器沒有該bean才會默認創建,那我們就自己創建一個注入到spring容器中:
在order 服務中:
@Configuration public class Config { @Bean public Request.Options feignRequestOptions() { Request.Options options = new Request.Options(2000, TimeUnit.MILLISECONDS, 2000, TimeUnit.MILLISECONDS, true); return options; } }
重啟,重新調用:
看到配置已經生效了:
我們這里readTimeout 設置了2秒,如果我們在product服務睡眠3s看看:
product 服務沒有睡眠時,正常情況調用結果如下:
product 服務代碼修改:
order 服務再次調用:
可見,跟我們想象的一樣
如果feign的超時時間設置為4s,而hystrix的熔斷時間設置為2s看看:
再次調用:
重點是product服務的日志打印:
證明order 服務熔斷了,但product 服務還是被調用了,說明feign的時間設置是沒問題的
根據上面分析,Hystrix的熔斷時間要大於Feign或Ribbon的connectTimeout+readTimeout
feign的超時時間如果要在application.yml中配置,改如何配置呢:
feign: hystrix: enabled: true client: config: default: #連接到目標的時間,此處會收到注冊中心啟動中的影響。設置為3秒鍾,如果注冊中心有明顯的不在線,基本是毫秒級熔斷拒絕 connectTimeout: 3000 #獲取目標連接后執行的最長時間,設置為32秒,即服務最長時 readTimeout: 32000
為何能這樣配置呢?
我們再次啟動order服務,調用跟蹤:
那ribbon的超時時間如何配置:
ribbon: ReadTimeout: 3000 ConnectTimeout: 3000
再次啟動測試:
那么有人要問了,如果feign和ribbon同時配置,那么以誰的為准,前面已經分析過了,這里再次分析:
重新調用跟蹤:
繼續跟蹤:
最后總結:
hystrix的熔斷時間配置通過yml配置沒法生效,可以通過配置類的方法來修改,feign的超時時間可以通過代碼或者yml配置,ribbon的超時時間可以通過yml來配置
feign和ribbon的超時時間只能二選一,只要feign的超時時間配置了,就以feign的為准,hystrix的超時時間要大於feign/riboon的connectTimeout+readTimeout的和
最后一張圖來總結: