你們在初次使用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.
log出自AbstractRibbonCommand.java
,那麼索性研究一下源碼。git
假設:github
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的超時時間是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
到這裏最前面的疑問已經解開了,可是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
get
一目瞭然,{serviceName}.ribbon.{propertyName}
就能夠了。源碼
感受ribbon和hytrix的配置獲取源碼略微有點亂,因此也致使你們在設置的時候有些無所適從。spring-cloud
的代碼一直在迭代,不管github上仍是文檔可能都相對滯後,這時候閱讀源碼而且動手debug一下是最能接近事實真相的了。