spring-cloud服务网关中的Timeout设置

标签: 基础技术 Spring Cloud timeout | 发表时间:2018-04-28 11:15 | 作者:TiuVe2
出处:http://www.importnew.com

大家在初次使用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 服务] 推荐:

微服务框架Spring Cloud介绍 Part2: Spring Cloud与微服务

- - skaka的博客
之前介绍过 微服务的概念与Finagle框架, 这个系列介绍Spring Cloud.. Spring Cloud还是一个相对较新的框架, 今年(2016)才推出1.0的release版本. 虽然Spring Cloud时间最短, 但是相比我之前用过的Dubbo和Finagle, Spring Cloud提供的功能最齐全..

大话 Spring Cloud

- - IT瘾-dev
研究了一段时间spring boot了准备向spirng cloud进发,公司架构和项目也全面拥抱了Spring Cloud. 在使用了一段时间后发现Spring Cloud从技术架构上降低了对大型系统构建的要求,使我们以非常低的成本(技术或者硬件)搭建一套高效、分布式、容错的平台,但Spring Cloud也不是没有缺点,小型独立的项目不适合使用.

Dubbo将积极适配Spring Cloud生态,Spring Cloud体系或将成为微服务的不二选择!

- - 程序猿DD
2016年,我在博客中发表过一篇 《微服务架构的基础框架选择:Spring Cloud还是Dubbo. 在这篇文章中,我主要对比了Spring Cloud与Dubbo所具备的能力,并阐述了个人推崇Spring Cloud的原因. 但是,最近各大技术社区出现了不少类似的文章,观点比较激进,对于Spring Cloud的褒扬远胜于Dubbo,但是这些评价很多都忽略了Spring Cloud与Dubbo在设计视角上的不同.

Spring Cloud Netflix构建微服务入门实践

- - 简单之美
在使用Spring Cloud Netflix构建微服务之前,我们先了解一下Spring Cloud集成的Netflix OSS的基础组件Eureka,对于Netflix的其他微服务组件,像Hystrix、Zuul、Ribbon等等本文暂不涉及,感兴趣可以参考官网文档. 这里,我们用最基础的Eureka来构建一个最基础的微服务应用,来演示如何构建微服务,了解微服务的基本特点.

使用Spring Cloud和Docker构建微服务架构

- - Oopsguy
原文: https://dzone.com/articles/microservice-architecture-with-spring-cloud-and-do. 作者:Alexander Lukyanchikov. 如何使用Spring Boot、Spring Cloud、Docker和Netflix的一些开源工具来构建一个微服务架构.

Spring Cloud 微服务的那点事 - CSDN博客

- -
微服务的概念源于2014年3月Martin Fowler所写的一篇文章“Microservices”. 微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值. 每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API).

spring-cloud服务网关中的Timeout设置

- - ImportNew
大家在初次使用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..

实用技巧:Spring Cloud中,如何优雅下线微服务?

- - 周立的博客 - 关注Spring Cloud、Docker
在生产环境中,服务的上下线是不可避免的,我们希望能够优雅地下线微服务. 本文基于Spring Boot 2.x + Spring Cloud Finchley讲解实际项目中优雅下线服务的四种方式,并探讨各方式的优缺点. 注:Spring Boot 1.x + Spring Cloud Edgware及之前的方式相同,但配置有区别,本文不做讨论.

一个基于Spring Cloud的微服务电商平台系统

- - 程序猿DD
年之计在于春,新年就要有新的打算,TJ君身边不少小伙伴都有点想在新的一年里开个网店的冲动,但是如何入手、如何开店都是个学问,需要好好研究,不过这也说明了电商行业的前景还是不错滴. 所以当TJ君今天留意到这个开源项目的时候,第一反应就是,可用. 说到mall4cloud,不得不先说下Mall4j. Mall4j是一个商用的提供多元化电商服务,满足企业多场景业务需求,为垂直行业提供专业的电商解决方案网站,提供多种成熟的电商配套服务,而mall4cloud则正是它的 开源版本.

Spring Cloud限流详解 | Spring Cloud|周立

- -
限流往往是一个绕不开的话题. 本文详细探讨在Spring Cloud中如何实现限流. Zuul上实现限流是个不错的选择,只需要编写一个过滤器就可以了,关键在于如何实现限流的算法. 常见的限流算法有漏桶算法以及令牌桶算法. https://www.cnblogs.com/LBSer/p/4083131.html,写得通俗易懂,你值得拥有,我就不拽文了.