Hystrix Fallback 解析

3,251 阅读3分钟

本文是在已经对 Hystrix 有初步认识的前提下,对 fallback 的一点解析。
引用来自
1.简书博客:Hystrix 使用指南(2):Fallback 详解
作者:编走编想
2.《Spring Cloud 微服务实战》
作者:翟永超

一、fallback 概述

降级是除了熔断以外, Hystrix 的另一个重要功能。fallback 是 Hystrix 命令执行失败时使用的后备方法,用来实现服务的降级处理逻辑。在 HystrixCommand 中可以通过重载 getFallback() 方法来实现服务降级逻辑,Hystrix 会在 run() 执行过程中出现错误、超时、线程池拒绝、短路熔断等情况时,执行 getFallback() 方法内的逻辑。

// HystrixCommand 中的 getFallback() 方法,在有后备方法时,可对其重载
protected R getFallback() {
    throw new UnsupportedOperationException("No fallback available.");
}

二、关于 fallback

(一)以下四种情况会触发 fallback

1. run() 执行过程中出现错误
通常,当 HystrixCommand 的主方法(run()) 中抛出异常时,便会触发 getFallback()。除了一个例外 —— HystrixBadRequestException。当抛出 HystrixBadRequestException,不论当前 Command 是否定义了 getFallback(),都不会触发,而是向上抛出异常。

如果实现业务时有一些异常希望能够向上抛出,而不是触发 Fallback 策略,便可以封装到 HystrixBadRequestException 中。

关于 HystrixBadRequestException另一个需要知道的是,它并不会被 Hystrix 计入失败。也就是说,不论一个 Command 抛出多少 HystrixBadRequestException,都不会导致熔断发生。

2. run() 执行超时
这种情况也很容易理解,在 Hystrix 中,执行超时也是失败的一种,所以同样也会触发 Fallback。

3. 线程池拒绝
线程池拒绝指的是 HystrixCommand 所使用的线程池没有足够的线程执行本次调用。Hystrix 使用的线程池的队列大小默认为 -1。此时,队列类型为 SynchronousQueue。当线程数不足时,任务会就被拒绝。这种情况也算是一种执行失败,所以也会出发 Fallback。

4. 断路器熔断
当断路器打开时,Hystrix 会直接执行 Fallback,而不会执行主方法。

(二)Fallback 的执行线程

Hystrix 用来执行 getFallback() 方法所使用的线程同执行 run() 方法使用的线程是来自同一个线程池。

因为 getFallback() 中的逻辑虽然通常为降级策略,但仍为程序功能的一部分,依旧需要使用同主逻辑相同的隔离策略。在默认情况下,即线程池隔离。

(三)Fallback 是否受超时时间控制

不受

getFallback() 的执行时间并不受 HystrixCommand 的超时时间的控制。所以,在使用 fallback 机制的时候,要避免 fallback 方法占用过多的线程。

默认情况下,为了避免 getFallback() 方法占用过多的资源,Hystrix 使用了信号量 Semaphore 对其进行资源隔离,默认并发度为10。但信号量的资源隔离的力度是有限的。

如果你在 getFallback() 方法中实现重试逻辑,同时 HystrixCommand 上设置的超时时间是1秒。当熔断发生时,因为你在 getFallback() 中再次调用同一个方法,且因为 getFallback() 不受超时时间的控制。当 TPS 大于 10 时,尽管主方法没有耗尽线程,但 getFallback() 方法也会把线程池耗尽。(假设线程池使用默认10的配置)