zoukankan      html  css  js  c++  java
  • spring-cloud服务网关中的Timeout设置

    本文转载自: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一下是最能接近事实真相的了。

  • 相关阅读:
    nodejs 单元测试框架api文档
    Pytest官方教程-22-API参考-Hooks
    【pytest】Hook 方法之 pytest_addoption :注册命令行参数
    k8s架构
    k8s 组件介绍-API Server API Server简介
    SpringCloud 应用在 Kubernetes 上的最佳实践 — 线上发布(可灰度)
    Elasticsearch 常见的 8 种错误及最佳实践
    Istio路由配置
    监控系统选型,这篇不可不读!
    logstash实现日志文件同步到elasticsearch深入详解
  • 原文地址:https://www.cnblogs.com/alimayun/p/11449089.html
Copyright © 2011-2022 走看看