欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识

原文出处: 大名Dean鼎 大家 次  来源:宝鼎软件 时间:2018-04-29

原文出处: 台甫Dean鼎

各人在初次利用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}就可以了。

    小结