由於測試 Feign + Hystrix 搭配模式下的降級(fallback)超時時間自定義問題,算是踩了個坑,而後就順便查+測試了下 Zuul、Ribbon + Hystrix 模式下分別怎麼設置html
測試這些東西費了很多力氣,由於這幾個模塊要麼搭配使用、要麼有內部依賴別的模塊、要麼對其餘模塊作了封裝,這個配置項就變得千奇百怪,並且網上的東西,一直以爲有個很"嚴重"的問題,就是版本不明,版本號都不同,解決方案或者說配置方式可能徹底不一樣,而不少的文章中也沒有說起他們用的是哪一個版本,搞得我是暈頭轉向(畢竟我不是這些服務模塊的開發者或者長期的使用者,不是很是瞭解這些東西的版本演進過程)java
因此這裏是查了很多的資料,測試經過了一些方案,也算是本身總結記錄一下git
注意!github
這裏都是基於有 Eureka 作服務中心爲前提的spring
這個栗子的源碼看這裏app
最基本的配置,是 Hystrix 本身的一長串配置:hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
,但在 Feign 模塊中,單獨設置這個超時時間不行,還要額外設置 Ribbon 的超時時間,好比:socket
hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 5000 ribbon: ReadTimeout: 5000 ConnectTimeout: 5000
關於 Hystrix 的配置,這裏有官方的說明:ide
Default Value | 1000 |
Default Property | hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds |
Instance Property | hystrix.command.HystrixCommandKey.execution.isolation.thread.timeoutInMilliseconds |
How to Set Instance Default | HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(int value) |
能夠看到實例配置中,替代 default 的,是 HystrixCommandKey,這個值在下面會說到工具
若是更進一步,想把超時時間細分到不一樣的 service 實例上也能夠實現,好比:學習
@FeignClient( value = "hello-service", fallback = MyFeignClientHystric.class) public interface MyFeignClient { @RequestMapping("/hello") String sayHelloByFeign(); @RequestMapping("/why") String sayWhyByFeign(); }
hystrix: command: "MyFeignClient#sayWhyByFeign()": execution: isolation: thread: timeoutInMilliseconds: 9000 default: execution: isolation: thread: timeoutInMilliseconds: 2000 ribbon: ReadTimeout: 5000 ConnectTimeout: 5000
這種寫法是把默認的超時時間改爲2秒,而把另一個自定義的 Feign 客戶端中的某方法超時時間定成9秒(格式是類名#方法名()
,若是方法有入參,也要把入參的類型拼上),這裏的 MyFeignClient#sayWhyByFeign()
就表明了上面說到的 commandKey
,而這種寫法,則是 Feign 模塊中特殊的:
ryanjbaxter commented on 26 JulIf you had a Feign client called MyClient and it had a method called search that took in a single String parameter than you would use the following property
hystrix.command.MyClient#search(String).execution.isolation.thread.timeoutInMilliseconds
看 issue 裏 Spring Cloud 的官方人員的說法,這種格式是他們進行的封裝,因此咱們要設置,就只能這麼寫
這個栗子的源碼看這裏
在使用 Ribbon 時,只須要配置 Hystrix 的超時時間就能夠生效,不須要額外配置 Ribbon 的超時時間,好比:
hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 9000
想細分服務超時時間時:
若是是同一個服務實例下的不一樣接口,想使用不一樣的超時時間,能夠把 @HystrixCommand
中的 commandKey
定義成不一樣的值,而後在 yml 中分別設置
@HystrixCommand( commandKey = "helloService-sayHello", fallbackMethod = "sayHelloDefault") public String sayHelloByRibbon() { return restTemplate.getForObject("http://HELLO-SERVICE/hello", String.class); } public String sayHelloDefault() { return "hello service error, this is default say hello method"; } @HystrixCommand( commandKey = "helloService-sayWhy", fallbackMethod = "sayWhyDefault") public String sayWhyByRibbon() { return restTemplate.getForObject("http://HELLO-SERVICE/why", String.class); } public String sayWhyDefault() { return "hello service error, this is default say why method"; }
hystrix: command: helloService-sayWhy: execution: isolation: thread: timeoutInMilliseconds: 5000 default: execution: isolation: thread: timeoutInMilliseconds: 1500
若是想統一設置同一個服務實例中各方法的超時時間,經測試,能夠把不一樣方法上的 commandKey
設置成相同的值,這樣在 yml 中對該 key 作超時配置就能同時生效了:
@HystrixCommand( commandKey = "helloService", fallbackMethod = "sayHelloDefault") public String sayHelloByRibbon() { return restTemplate.getForObject("http://HELLO-SERVICE/hello", String.class); } public String sayHelloDefault() { return "hello service error, this is default say hello method"; } @HystrixCommand( commandKey = "helloService", fallbackMethod = "sayWhyDefault") public String sayWhyByRibbon() { return restTemplate.getForObject("http://HELLO-SERVICE/why", String.class); } public String sayWhyDefault() { return "hello service error, this is default say why method"; }
hystrix: command: helloService: execution: isolation: thread: timeoutInMilliseconds: 5000 default: execution: isolation: thread: timeoutInMilliseconds: 1000
這個栗子的源碼看這裏,Zuul 中的降級是用了 FallbackProvider
,簡單的使用能夠看我源碼中的 HelloFallbackProvider.java 和 HiFallbackProvider.java,我也是參考了官方的文檔說明和例子
zuul 中配置超時時間,據官方的介紹,分兩種狀況:
ribbon.ReadTimeout
和 ribbon.SocketTimeout
設置zuul.host.connect-timeout-millis
和 zuul.host.socket-timeout-millis
設置由於個人代碼中是用 serviceId 的方式,因此參考了第一種配置,好比:
zuul: routes: helloService: path: /hello-service/** serviceId: hello-service hiService: path: /hi-service/** serviceId: hi-service ribbon: ConnectTimeout: 5000 ReadTimeout: 5000
Ribbon 的配置項還能夠加一個 ClientName
爲前綴(這個方法的出處在官方的 wiki),區分不一樣客戶端下的配置,這個 ClientName
我是直接用了 serviceId,測試了正常,但還能夠用或者說應該用什麼值,這個我尚未找到官方的說明。。
zuul: routes: helloService: path: /hello-service/** serviceId: hello-service hiService: path: /hi-service/** serviceId: hi-service hello-service: ribbon: ConnectTimeout: 5000 ReadTimeout: 5000 hi-service: ribbon: ConnectTimeout: 500 ReadTimeout: 500 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 3000
另外還作了測試,若是同時配置了 Ribbon 和 Hystrix 的超時時間,則以最小的爲準,好比上述的配置中,若是 hi-service 的接口調用超過了 0.5 秒,則就會觸發超時
目前的學習和測試結果來看:
commandKey
來實現超時時間的配置commandKey
,咱們不能自定義,因此同一個 FeignClient 下的服務接口不能方便的統一配置,若是有相應的業務需求,或許只能對每一個特殊的接口方法作獨立的超時配置(找到新方法的話再回來更新)