Zuul、Ribbon、Feign、Hystrix使用時的超時時間(timeout)設置問題

本文轉載自:https://priesttomb.github.io/,謝謝作者的分享

寫在前面

因爲測試 Feign + Hystrix 搭配模式下的降級(fallback)超時時間自定義問題,算是踩了個坑,然後就順便查+測試了下 Zuul、Ribbon + Hystrix 模式下分別怎麼設置
測試這些東西費了不少力氣,因爲這幾個模塊要麼搭配使用、要麼有內部依賴別的模塊、要麼對其他模塊做了封裝,這個配置項就變得千奇百怪,而且網上的東西,一直覺得有個很”嚴重”的問題,就是版本不明,版本號都不一樣,解決方案或者說配置方式可能完全不同,而很多的文章中也沒有提及他們用的是哪個版本,搞得我是暈頭轉向(畢竟我不是這些服務模塊的開發者或者長期的使用者,不是非常瞭解這些東西的版本演進過程)
所以這裏是查了不少的資料,測試通過了一些方案,也算是自己總結記錄一下

注意!

這裏都是基於有 Eureka 做服務中心爲前提的

工具

Eclipse Oxygen
Spring Boot 2.0.5.RELEASE
Spring Cloud Finchley.SR1
Eureka 1.9.3
Zuul 1.3.1
Ribbon 2.2.5
Feign 9.5.1
Hystrix 1.5.12

Feign + Hystrix

這個栗子的源碼看這裏

0. 默認基本配置

最基本的配置,是 Hystrix 自己的一長串配置:hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds,但在 Feign 模塊中,單獨設置這個超時時間不行,還要額外設置 Ribbon 的超時時間,比如:

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000

ribbon:
  ReadTimeout: 5000
  ConnectTimeout: 5000

關於 Hystrix 的配置,這裏有官方的說明:
在這裏插入圖片描述
可以看到實例配置中,替代 default 的,是 HystrixCommandKey,這個值在下面會說到

1. 不同實例分別配置

如果更進一步,想把超時時間細分到不同的 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 Jul

If 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

這個栗子的源碼看這裏

0. 默認基本配置

在使用 Ribbon 時,只需要配置 Hystrix 的超時時間就可以生效,不需要額外配置 Ribbon 的超時時間,比如:

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 9000
1. 不同實例分別配置

想細分服務超時時間時:
如果是同一個服務實例下的不同接口,想使用不同的超時時間,可以把 @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

這個栗子的源碼看這裏,Zuul 中的降級是用了 FallbackProvider,簡單的使用可以看我源碼中的 HelloFallbackProvider.java 和 HiFallbackProvider.java,我也是參考了官方的文檔說明和例子

0. 默認基本配置

zuul 中配置超時時間,據官方的介紹,分兩種情況:

  • 用 serviceId 進行路由時,使用 ribbon.ReadTimeout 和 ribbon.SocketTimeout 設置
  • 用指定 url 進行路由時,使用 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
1. 不同實例分別配置

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 秒,則就會觸發超時

總結

目前的學習和測試結果來看:
單純的 Ribbon + Hystrix 搭配使用時,配置是最靈活的,兩者沒有相互干涉,可以自由定義 commandKey 來實現超時時間的配置
Feign + Hystrix 搭配時,由於 Feign 封裝了 Hystrix 所需的 commandKey,我們不能自定義,所以同一個 FeignClient 下的服務接口不能方便的統一配置,如果有相應的業務需求,或許只能對每個特殊的接口方法做獨立的超時配置(找到新方法的話再回來更新)
Zuul + Hystrix 搭配時,和上述的情況相反,能對不同服務實例做不同的超時配置,但不能再細化到服務下的具體接口方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章