當前位置:
首頁 > 知識 > spring-cloud 服務網關中的 Timeout 設置

spring-cloud 服務網關中的 Timeout 設置

(點擊

上方公眾號

,可快速關注)




來源:大名Dean鼎,


www.deanwangpro.com/2018/04/13/zuul-hytrix-ribbon-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> 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一下是最能接近事實真相的了。




看完本文有收穫?請轉發分享給更多人


關注「ImportNew」,提升Java技能


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 ImportNew 的精彩文章:

構造模式實踐

TAG:ImportNew |