本文转载自:https://segmentfault.com/a/1190000014370360

大家在初次使用spring-cloud的gateway的时候,肯定会被里面各种的Timeout搞得晕头转向。hytrix有设置,ribbon也有。我们一开始也是乱设一桶,Github上各种项目里也没几个设置正确的。对Timeout的研究源于一次log中的warning

The Hystrix timeout of 60000 ms for the command "foo" is set lower than the combination of the Ribbon read and connect timeout, 200000ms.

hytrix超时时间

log出自AbstractRibbonCommand.java,那么索性研究一下源码。

假设:

  • 这里gateway会请求一个serviceName=foo的服务
protected static int getHystrixTimeout(IClientConfig config, String commandKey) {
int ribbonTimeout = getRibbonTimeout(config, commandKey);
DynamicPropertyFactory dynamicPropertyFactory = DynamicPropertyFactory.getInstance(); // 获取默认的hytrix超时时间
int defaultHystrixTimeout = dynamicPropertyFactory.getIntProperty("hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds",
0).get();
// 获取具体服务的hytrix超时时间,这里应该是hystrix.command.foo.execution.isolation.thread.timeoutInMilliseconds
int commandHystrixTimeout = dynamicPropertyFactory.getIntProperty("hystrix.command." + commandKey + ".execution.isolation.thread.timeoutInMilliseconds",
0).get();
int hystrixTimeout;
// hystrixTimeout的优先级是 具体服务的hytrix超时时间 > 默认的hytrix超时时间 > ribbon超时时间
if(commandHystrixTimeout > 0) {
hystrixTimeout = commandHystrixTimeout;
}
else if(defaultHystrixTimeout > 0) {
hystrixTimeout = defaultHystrixTimeout;
} else {
hystrixTimeout = ribbonTimeout;
}
// 如果默认的或者具体服务的hytrix超时时间小于ribbon超时时间就会警告
if(hystrixTimeout < ribbonTimeout) {
LOGGER.warn("The Hystrix timeout of " + hystrixTimeout + "ms for the command " + commandKey +
" is set lower than the combination of the Ribbon read and connect timeout, " + ribbonTimeout + "ms.");
}
return hystrixTimeout;
}

紧接着,看一下我们的配置是什么

hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 60000 ribbon:
ReadTimeout: 50000
ConnectTimeout: 50000
MaxAutoRetries: 0
MaxAutoRetriesNextServer: 1

ribbon超时时间

这里ribbon的超时时间是50000ms,那么为什么log中写的ribbon时间是200000ms?

继续分析源码:

protected static int getRibbonTimeout(IClientConfig config, String commandKey) {
int ribbonTimeout;
// 这是比较异常的情况,不说
if (config == null) {
ribbonTimeout = RibbonClientConfiguration.DEFAULT_READ_TIMEOUT + RibbonClientConfiguration.DEFAULT_CONNECT_TIMEOUT;
} else {
// 这里获取了四个参数,ReadTimeout,ConnectTimeout,MaxAutoRetries, MaxAutoRetriesNextServer
int ribbonReadTimeout = getTimeout(config, commandKey, "ReadTimeout",
IClientConfigKey.Keys.ReadTimeout, RibbonClientConfiguration.DEFAULT_READ_TIMEOUT);
int ribbonConnectTimeout = getTimeout(config, commandKey, "ConnectTimeout",
IClientConfigKey.Keys.ConnectTimeout, RibbonClientConfiguration.DEFAULT_CONNECT_TIMEOUT);
int maxAutoRetries = getTimeout(config, commandKey, "MaxAutoRetries",
IClientConfigKey.Keys.MaxAutoRetries, DefaultClientConfigImpl.DEFAULT_MAX_AUTO_RETRIES);
int maxAutoRetriesNextServer = getTimeout(config, commandKey, "MaxAutoRetriesNextServer",
IClientConfigKey.Keys.MaxAutoRetriesNextServer, DefaultClientConfigImpl.DEFAULT_MAX_AUTO_RETRIES_NEXT_SERVER);
// 原来ribbonTimeout的计算方法在这里,以上文的设置为例
// ribbonTimeout = (50000 + 50000) * (0 + 1) * (1 + 1) = 200000
ribbonTimeout = (ribbonReadTimeout + ribbonConnectTimeout) * (maxAutoRetries + 1) * (maxAutoRetriesNextServer + 1);
}
return ribbonTimeout;
}

可以看到ribbonTimeout是一个总时间,所以从逻辑上来讲,作者希望hystrixTimeout要大于ribbonTimeout,否则hystrix熔断了以后,ribbon的重试就都没有意义了。

ribbon单服务设置

到这里最前面的疑问已经解开了,但是hytrix可以分服务设置timeout,ribbon可不可以? 源码走起,这里看的文件是DefaultClientConfigImpl.java

// 这是获取配置的入口方法,如果是null,那么用默认值
// 所有ribbon的默认值的都在该类中设置了,可以自己看一下
public <T> T get(IClientConfigKey<T> key, T defaultValue) {
T value = get(key);
if (value == null) {
value = defaultValue;
}
return value;
} // 这是核心方法
protected Object getProperty(String key) {
if (enableDynamicProperties) {
String dynamicValue = null;
DynamicStringProperty dynamicProperty = dynamicProperties.get(key);
// dynamicProperties其实是一个缓存,首次访问foo服务的时候会加载
if (dynamicProperty != null) {
dynamicValue = dynamicProperty.get();
}
// 如果缓存没有,那么就再获取一次,注意这里的getConfigKey(key)是生成key的方法
if (dynamicValue == null) {
dynamicValue = DynamicProperty.getInstance(getConfigKey(key)).getString();
// 如果还是没有取默认值,getDefaultPropName(key)生成key的方法
if (dynamicValue == null) {
dynamicValue = DynamicProperty.getInstance(getDefaultPropName(key)).getString();
}
}
if (dynamicValue != null) {
return dynamicValue;
}
}
return properties.get(key);
}

以我们的服务为例:
getConfigKey(key) returns foo.ribbon.ReadTimeout
getDefaultPropName(key) returns ribbon.ReadTimeout

一目了然,{serviceName}.ribbon.{propertyName}就可以了。

小结

感觉ribbon和hytrix的配置获取源码略微有点乱,所以也导致大家在设置的时候有些无所适从。spring-cloud的代码一直在迭代,无论github上还是文档可能都相对滞后,这时候阅读源码并且动手debug一下是最能接近事实真相的了。

spring-cloud服务网关中的Timeout设置的更多相关文章

  1. Spring Cloud中Feign如何统一设置验证token

    代码地址:https://github.com/hbbliyong/springcloud.git 原理是通过每个微服务请求之前都从认证服务获取认证之后的token,然后将token放入到请求头中带过 ...

  2. spring cloud 配置纲要Properties

    名称 默认 描述 encrypt.fail-on-error true 标记说,如果存在加密或解密错误,进程将失败. encrypt.key   对称密钥.作为一个更强大的替代方案,考虑使用密钥库. ...

  3. Spring cloud properties与yml配置说明

    encrypt说明 名称 默 认 描述 encrypt.fail-on-error true 标记说,如果存在加密或解密错误,进程将失败. encrypt.key 对称密钥.作为一个更强大的替代方案, ...

  4. Spring Cloud官方文档中文版-Spring Cloud Config(上)

    官方文档地址为:http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#spring-cloud-feign 文中例子我做了一些测试在:http ...

  5. 【SFA官方翻译】Spring WebFlux和Spring Cloud进行响应式微服务开发

    源码,修正一些错误: https://github.com/bigben0123/sample-spring-cloud-webflux 原创 SpringForAll社区 2018-05-18 作者 ...

  6. Spring Cloud Config中文文档

    https://springcloud.cc/spring-cloud-config.html 目录 快速开始 客户端使用 Spring Cloud Config服务器 环境库 健康指标 安全 加密和 ...

  7. Spring Cloud Consul

    1.2.0.RELEASE 该项目通过自动配置并绑定到Spring环境和其他Spring编程模型成语,为Spring Boot应用程序提供Consul集成.通过几个简单的注释,您可以快速启用和配置应用 ...

  8. Spring Cloud config之一:分布式配置中心入门介绍

    Spring Cloud Config为服务端和客户端提供了分布式系统的外部化配置支持.配置服务器为各应用的所有环境提供了一个中心化的外部配置.它实现了对服务端和客户端对Spring Environm ...

  9. spring cloud连载第三篇之Spring Cloud Netflix

    1. Service Discovery: Eureka Server(服务发现:eureka服务器) 1.1 依赖 <dependency> <groupId>org.spr ...

随机推荐

  1. C++Builder中注册表的操作

    僮骶头浅5募虻チ耍旅嫖揖鸵砸桓鍪道此得鱐Registry类的用法.首先,先介绍一下TRegistry的属性和方法:TRegistry类一共有四个属性.属性 类型 描述CurrentKey int ...

  2. 纯CSS3实现图片展示特效

    本文中要实现的一个纯CSS3的图片展示特效,以前只能用JavaScript实现,可想而知会受到多方面的限制,特别是性能.而今天我们将用简单的CSS3代码实现,你会发现它的动画效果在现代浏览器的帮助下无 ...

  3. 2019-11-9-win10-支持默认把触摸提升-Pointer-消息

    title author date CreateTime categories win10 支持默认把触摸提升 Pointer 消息 lindexi 2019-11-09 15:32:31 +0800 ...

  4. Axios的get和post请求写法

    执行get请求 // 为给定 ID 的 user 创建请求 axios.get('/user?ID=12345') .then(function (response) { console.log(re ...

  5. idea-----Intellij IDEA配置tomcat(非maven项目)

    Intellij IDEA配置tomcat(非maven项目) 引用: https://blog.csdn.net/springlovejava/article/details/78570241 ID ...

  6. CentOS7配置Docker镜像加速器

    1. 将默认的配置文件复制出来 cp -n /lib/systemd/system/docker.service /etc/systemd/system/docker.service 2. 将加速器地 ...

  7. odoo js

    1.相关库/框架 主要:jQuery(使用1.8.3,如果使用新版本,其他jQuery插件也要升级或修改).Underscore.QWeb 其他:都在addons\web\static\lib路径下. ...

  8. 容斥原理——hdu1796

    /* 遇到这种题一般用dfs,枚举起点来做 但是本题如何进行容斥? 比如以x为起点,第一步dfs到y,那么因子有lcm(x,y)的 所有数要被减掉(容斥中偶数是减法) 然后第二步dfs到z,那么因子有 ...

  9. 期望——邮票收集问题lightoj1342

    邮票手机问题: 有n种类型的邮票,问将所有的类型的邮票全部收集起来所要的收集次数期望是多少. 设dp[i]为已经收集了i种类型的票,还要收集n-i种的次数的期望. dp[n]=0; 递推式: dp[i ...

  10. ES6数组对象新增方法

    1. Array.from() Array.from方法用于将两类对象转为真正的数组:类数组的对象( array-like object )和可遍历( iterable )的对象(包括 ES6 新增的 ...