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

你們在初次使用spring-cloud的gateway的時候,確定會被裏面各類的Timeout搞得暈頭轉向。hytrix有設置,ribbon也有。咱們一開始也是亂設一桶,Github上各類項目裏也沒幾個設置正確的。對Timeout的研究源於一次log中的warningjava

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,那麼索性研究一下源碼。git

假設:github

  • 這裏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;
}

緊接着,看一下咱們的配置是什麼spring

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 60000
            
ribbon:
  ReadTimeout: 50000
  ConnectTimeout: 50000
  MaxAutoRetries: 0
  MaxAutoRetriesNextServer: 1

ribbon超時時間

這裏ribbon的超時時間是50000ms,那麼爲何log中寫的ribbon時間是200000ms?緩存

繼續分析源碼:debug

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的重試就都沒有意義了。code

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.ReadTimeoutget

一目瞭然,{serviceName}.ribbon.{propertyName}就能夠了。源碼

小結

感受ribbon和hytrix的配置獲取源碼略微有點亂,因此也致使你們在設置的時候有些無所適從。spring-cloud的代碼一直在迭代,不管github上仍是文檔可能都相對滯後,這時候閱讀源碼而且動手debug一下是最能接近事實真相的了。

相關文章
相關標籤/搜索