背景:
在网上看过很多博客,都是在yml里配置hystrix和ribbon的超时时间,但实践后发现根本没效果,如下面的配置:
一.先看测试环境搭建:
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)来修改默认的配置,也就是上面我们自己定义的配置类
熔断器的熔断时间是从调用下面的方法开始计算的:
三.ribbon超时时间怎么设置?
我们继续跟进刚才的调用方法:
先看看这个类的值:
在这里默认连接时间是10s,读取时间是60s,那么这个类是怎么创建的呢?
从上面可以知道,Options对象默认已经有个时间配置了,然而我们继续跟踪代码:
我们看这里:
Options对象经过getClientConfig(options, clientName) 方法,就从10s的连接时间变成了1s,60s的读取时间也变成了1s
继续跟进:
至此,我们知道了,默认情况调用第三方服务时,超时时间是1s,那么我们该如何修改呢?
我们回到这里:
这里说了,如果容器没有该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 服务再次调用:
可见,跟我们想象的一样
如果ribbon的超时时间设置为4s,而hystrix的熔断时间设置为2s看看:
再次调用:
重点是product服务的日志打印:
证明order 服务熔断了,但product 服务还是被调用了,说明ribbon的时间设置是没问题的
根据上面分析,Hystrix的熔断时间要大于Ribbon的connectTimeout+readTimeout
hystrix 超时时间和ribbon的connectTimeout 以及readTimeout 的配置以及原理分析
原文:https://www.cnblogs.com/yangxiaohui227/p/13031370.html