Hystrix与Ribbon不得不说的事 - 超时配置

前面的小节里我们做了几个小练习,熟悉了Hystrix服务降级的使用,这一节我们来学习一下Ribbon和Hystrix共同作用时要注意的地方-超时配置。之前我们学习了很复杂的Ribbon超时计算公式-求极限,那么再加上Hystrix情况会变得更复杂吗?

数学课代表之争

超时降级 - 规避与Ribbon共同作用时的坑 - 图1
我们知道Feign集成了Ribbon和Hystrix两个组件,它俩都各自有一套超时配置,话说一个班级不能有两个数学课代表,那到底哪个超时配置是最终生效的那个呢?
我们先来复习一下Ribbon的超时时间计算公式:

  1. 最大超时时间=
  2. (连接超时时间+接口超时时间)*(当前节点重试次数+1)*(换节点重试次数+1

假如经过上述计算,Ribbon的超时时间是2000ms,那么Hystrix的超时时间应该设置成多少才合理呢?我们先来看看Hystrix的默认全局配置:

  1. hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=1000

以上全局配置设置了Hystrix的熔断时间为1000ms。这里Hystrix的超时时间设置比Ribbon配置的时间短,那么不等Ribbon重试结束,Hystrix判定超时后就会直接执行熔断逻辑。因此,Hystrix和Ribbon是一个共同作用的关系,谁先到达超时指标就会率先起作用。
通常来讲,Hystrix的熔断时间要比Ribbon的最长超时时间设置的略长一些,这样就可以让Ribbon的重试机制充分发挥作用,以免出现还没来得及重试就进入fallback逻辑的情况发生。
那如果我们有一些接口对响应时间的要求特别高,比如说商品详情页接口,元数据必须在2s以内加载返回,那我们怎么针对方法设置更细粒度的Hystrix超时限制?

Hystrix方法级别超时控制

我们有两个方式针对Method级别做超时判定,我们先来看两个配置例子:

基于方法签名的超时配置

  1. hystrix.command.ClassName#methodName(Integer).execution.isolation.thread.timeoutInMilliseconds=1000

上面的配置是基于“方法签名”生成的,其中ClassName#methodName(Integer)就是一串类名+方法名+方法参数的组合,对于复杂的方法,人工拼出这一套组合字符串也挺费脑子的,Feign提供了一个简单的工具根据反射机制生成字符串:

  1. Feign.configKey(MyService.class, MyService.class.getMethod("findFriend", Integer.class))

如果说上面的配置对于你来说太过于麻烦,那你可以采用下面的一种。

基于CommandKey的配置

我们在声明@HystrixCommand的时候,可以给方法指定一个CommandKey,就像下面这样:

  1. @HystrixCommand(commandKey = "myKey"fallbackMethod = "fallback")

这里我们给方法指定了commandKey为mykey,接下来只要使用myKey来替换方法签名就可以实现同样的效果,是不是更简单了?

  1. hystrix.command.myKey.execution.isolation.thread.timeoutInMilliseconds=1000

小结

这一小节我们知道了Hystrix和Ribbon共同作用的时候如何判断超时时间,接下来,我们就来点烧脑的,去源码里探秘Hystrix的降级触发方式。
学习Tips:对于小型应用来说往往不需要降级措施,设计降级方案会增加系统复杂度和维护成本,我们尽量不要为了降级而降级,这样反而是画蛇添足了。也就是说,学习了一项新技术,未必就要生搬硬套应用在自己的项目中。技术只有使用在合适的场景下才能发挥真正的作用。