各人在初次利用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
,那么索性研究一下源码。
假设:
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}
就可以了。
小结