关于Feign的超时详解:

Spring Cloud微服务架构中,大部分公司都是利用Open Feign进行服务间的调用,而比较简单的业务使用默认配置是不会有多大问题的,但是如果是业务比较复杂,服务要进行比较繁杂的业务计算,那后台很有可能会出现Read Timeout这个异常。

1、关于hystrix的熔断超时

如果Feign开启了熔断,必须要重新设置熔断超时的时间,因为默认的熔断超时时间太短了,只有1秒,这容易导致业务服务的调用还没完成然后超时就被熔断了。

如何配置熔断超时:

#Feign如何开启熔断
feign.hystrix.enabled=true #是否开始超时熔断,如果为false,则熔断机制只在服务不可用时开启(spring-cloud-starter-openfeign中的HystrixCommandProperties默认为true)
hystrix.command.default.execution.timeout.enabled=true #设置超时熔断时间(spring-cloud-starter-openfeign中的HystrixCommandProperties默认为1000毫秒)
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000

注意:关于hystrixapplication.properties配置是没提示的,但是HystrixCommandProperties是会获取的。

// 构造函数
protected HystrixCommandProperties(HystrixCommandKey key, HystrixCommandProperties.Setter builder, String propertyPrefix) { // .... 省略很多其他配置 // propertyPrefix:hystrix,key:default
this.executionTimeoutInMilliseconds = getProperty(propertyPrefix, key, "execution.isolation.thread.timeoutInMilliseconds", builder.getExecutionIsolationThreadTimeoutInMilliseconds(), default_executionTimeoutInMilliseconds);
} // 具体获取属性的方法
private static HystrixProperty<String> getProperty(String propertyPrefix, HystrixCommandKey key, String instanceProperty, String builderOverrideValue, String defaultValue) {
return HystrixPropertiesChainedProperty.forString().add(propertyPrefix + ".command." + key.name() + "." + instanceProperty, builderOverrideValue).add(propertyPrefix + ".command.default." + instanceProperty, defaultValue).build();
}

2、关于Ribbon超时。

Feign调用默认是使用Ribbon进行负载均衡的,所以我们还需要了解关于Ribbon的超时。

①、Feign的调用链路

看一下Feign的请求是否有使用Ribbon的超时时间,而且是如何读取Ribbon的超时时间的?

(1)、org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient#execute

(2)、com.netflix.client.AbstractLoadBalancerAwareClient#executeWithLoadBalancer(S, com.netflix.client.config.IClientConfig)

(3)、org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory#create

	​创建Client,这里会判断对应ClientName的链接Client是否创建过,如果创建过复用之前的Client;
如果不存在则创建一个并且放入cache缓存。
public FeignLoadBalancer create(String clientName) {
FeignLoadBalancer client = this.cache.get(clientName);
if(client != null) {
return client;
}
IClientConfig config = this.factory.getClientConfig(clientName);
ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
ServerIntrospector serverIntrospector = this.factory.getInstance(clientName, ServerIntrospector.class);
// 判断是否有重试
client = loadBalancedRetryFactory != null ? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,
loadBalancedRetryFactory) : new FeignLoadBalancer(lb, config, serverIntrospector);
this.cache.put(clientName, client);
return client;
}

(4)、com.netflix.client.AbstractLoadBalancerAwareClient#executeWithLoadBalancer(S, com.netflix.client.config.IClientConfig)

	​负载均衡器抽象类

(5)、org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer#execute

​	Feign的负载均衡器实现类。到这里我们可以看到,连接超时和读超时的配置都在这里:
如果application.properties配置文件中的超时时间不为空,则使用配置的超时时间。
如果为空则使用默认值,而从FeignLoadBalancer的构造函数可以看到,默认值也是取的RibbonProperties的默认超时时间。
public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride)
throws IOException {
Request.Options options;
// 设置超时时间。,如果orride的配置为空,则用默认值
if (configOverride != null) {
RibbonProperties override = RibbonProperties.from(configOverride);
options = new Request.Options(
override.connectTimeout(this.connectTimeout),
override.readTimeout(this.readTimeout));
}
else {
options = new Request.Options(this.connectTimeout, this.readTimeout);
}
// 发起请求
Response response = request.client().execute(request.toRequest(), options);
return new RibbonResponse(request.getUri(), response);
} // 构造函数
public FeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig, ServerIntrospector serverIntrospector) {
super(lb, clientConfig);
this.setRetryHandler(RetryHandler.DEFAULT);
this.clientConfig = clientConfig;
this.ribbon = RibbonProperties.from(clientConfig);
RibbonProperties ribbon = this.ribbon;
this.connectTimeout = ribbon.getConnectTimeout();
this.readTimeout = ribbon.getReadTimeout();
this.serverIntrospector = serverIntrospector;
}

②、Ribbon的默认超时时间

RibbonClientConfiguration中:

public static final int DEFAULT_CONNECT_TIMEOUT = 1000;
public static final int DEFAULT_READ_TIMEOUT = 1000;

③、如何自定义Ribbon超时时间

首先,RibbonProperties的超时时间的读取的源码如下:

public Integer getConnectTimeout() {
return (Integer)this.get(CommonClientConfigKey.ConnectTimeout);
} public Integer getReadTimeout() {
return (Integer)this.get(CommonClientConfigKey.ReadTimeout);
}

然后,可以在CommonClientConfigKey中可以看到两个超时时间的名称:

// ConnectTimeout:
public static final IClientConfigKey<Integer> ConnectTimeout = new CommonClientConfigKey<Integer>("ConnectTimeout") {}; // ReadTimeout:
public static final IClientConfigKey<Integer> ReadTimeout = new CommonClientConfigKey<Integer>("ReadTimeout") {};

然后,在IClientConfig的默认实现类:DefaultClientConfigImpl中,可以发现Ribbon配置的前缀

public static final String DEFAULT_PROPERTY_NAME_SPACE = "ribbon";

所以,最后Ribbon该这么配置超时时间:

ribbon.ConnectTimeout=5000
ribbon.ReadTimeout=5000

总结

如何配置好HystrixRibbon的超时时间呢?

其实是有套路的。因为Feign的请求:其实是Hystrix+RibbonHystrix在最外层,然后再到Ribbon,最后里面的是http请求。所以说。Hystrix的熔断时间必须大于Ribbon的 ( ConnectTimeout + ReadTimeout )。而如果Ribbon开启了重试机制,还需要乘以对应的重试次数,保证在Ribbon里的请求还没结束时,Hystrix的熔断时间不会超时。

【Spring Cloud 源码解读】之 【如何配置好OpenFeign的各种超时时间!】的更多相关文章

  1. 【Spring Cloud 源码解读】之 【这也太神奇了,RestTemplate加上一个@LoadBalanced注解就能实现负载均衡!】

    前提概要: 前天,有个前端大佬问了我两个问题:为啥不引入Ribbon依赖就能使用Ribbon?为啥RestTemplate加上@LoadBalanced注解就能负载均衡了?我也表示很疑惑,而我自己其实 ...

  2. Mybatis源码解读-SpringBoot中配置加载和Mapper的生成

    本文mybatis-spring-boot探讨在springboot工程中mybatis相关对象的注册与加载. 建议先了解mybatis在spring中的使用和springboot自动装载机制,再看此 ...

  3. Spring AMQP 源码分析 08 - XML 配置

    ### 准备 ## 目标 通过 XML 配置文件使用 Spring AMQP ## 前置知识 <Spring AMQP 源码分析 07 - MessageListenerAdapter> ...

  4. Spring Cloud源码分析(四)Zuul:核心过滤器

    通过之前发布的<Spring Cloud构建微服务架构(五)服务网关>一文,相信大家对于Spring Cloud Zuul已经有了一个基础的认识.通过前文的介绍,我们对于Zuul的第一印象 ...

  5. Spring:源码解读Spring IOC原理

    Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. I ...

  6. Spring IoC源码解读——谈谈bean的几种状态

    阅读Spring IoC部分源码有一段时间了,经过不断的单步调试和参阅资料,对Spring容器中bean管理有了一定的了解.这里从bean的几个状态的角度出发,研究下IoC容器. 一.原材料 Xml中 ...

  7. spring beans源码解读之 ioc容器之始祖--DefaultListableBeanFactory

    spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说, DefaultL ...

  8. spring beans源码解读

    spring beans下面有如下源文件包: org.springframework.beans, 包含了操作java bean的接口和类.org.springframework.beans.anno ...

  9. spring beans源码解读之--总结篇

    spring beans下面有如下源文件包: org.springframework.beans, 包含了操作java bean的接口和类.org.springframework.beans.anno ...

随机推荐

  1. vue init定制团队模板使用方法

    每次做项目都要自己搭建项目目录,或者换了公司就的重新搭建项目目录,是不是很麻烦呢?有没有想过一次性把项目目录搭建好,以后直接用呢?你首先想到的可能是复制自己原来的项目,然后删除.修改等等.然而有个更方 ...

  2. 最新版本的ADT使用问题

    昨天把androidsdk和adt更新到最新版本,android sdk r22版本. 更新完后原来的项目打包后出现第三方JAR包找不到,网上搜了半天终于找到问题所在: 新版本多了一个Android ...

  3. laravel 授权使用gate门类

    第一:先注册 第二:使用方式三种 路由中:Route::group(['middleware'=>'can:system'],function() {}) 模板中:@can("syst ...

  4. JS正则验证两位小数,验证数字最简单正则表达式大全

    <h3>输入完按回车后即可验证!</h3> 正整数: <input type="text" size="20" onkeydown ...

  5. mysql基础(库、表相关)

    一. mysql支持的数据类型 1.1 mysql支持的数字类型: TINYINT 1 字节 (-128,127) (0,255) 小整数值 SMALLINT 2 字节 (-32 768,32 767 ...

  6. [转载] 使用StAX解析xml

    StAX 概述 从一开始,Java API for XML Processing (JAXP) 就提供了两种方法来处理 XML:文档对象模型(DOM)方法是用标准的对象模型表示 XML 文档:Simp ...

  7. H3C HDLC协议使用限制

  8. Gyn 100989 "1D Cafeteria (B)"(set+lower_bound)

    传送门 •题意 某自助餐厅有 n 张桌子,桌子编号为 1~n,其中第 i 张桌子可容纳 ai 个人: 有两种操作: (1)in x : 有 x 个人来这家餐厅吃饭,需要找一个可容纳 x 人的桌子,并满 ...

  9. 【p083】传球游戏

    Time Limit: 1 second Memory Limit: 50 MB [问题描述] 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏. 游戏规则是这样 ...

  10. Spring Data -Specification用法和常用查询方法(in,join,equal等)

    Spring Data -Specification用法和常用查询方法(in,join,equal等) 前言 入门例子 Repository层常用写法 Specification 的用法 总结 前言 ...