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

大家在初次使用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 get(IClientConfigKey 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一下是最能接近事实真相的了。为了帮助大家少走弯路,我请BAT大厂工作的同事总结出一套技术视频,涵盖Java工程化、高性能及分布式、性能调优、Spring、Netty源码分析和大数据等知识点,大家可以通过扫码进群下载资料,其实我自己也比较喜欢技术,群里有一些阿里大牛,也有一线互联网的资深HR,最近在面试的朋友或者在找工作的可以进来看看哦!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,600评论 18 139
  • (git上的源码:https://gitee.com/rain7564/spring_microservices_...
    sprainkle阅读 9,331评论 13 33
  • pyspark.sql模块 模块上下文 Spark SQL和DataFrames的重要类: pyspark.sql...
    mpro阅读 9,446评论 0 13
  • Android音频系统详解 参考好文: Android 音频系统:从 AudioTrack 到 AudioFlin...
    爱雨520阅读 13,406评论 2 7
  • 说文说字 题目叫《说文说字》?为何不叫《说文解字》?《说文解字》是研究汉字的经典著作,是大师的干的活。解,为人解惑...
    风起龙飞阅读 360评论 3 10