15.1 理解断路器模式

15.1 理解断路器模式

断路器模式是随着Michael Nygard的Release It!(第2版,PragmaticBookshelf,2018)一书流行起来的,解决了我们所编写的代码可能会失败的问题。很重要的一点在于,即便是失败,它也能够优雅地失败。这个强大的模式在微服务环境中会更加关键,因为在这种环境下避免跨调用堆栈产生级联失败非常重要。

相对来讲,断路器模式的理念很简单,非常类似于现实世界中的电路断路器,这也是它得名的由来。在电路断路器中,当开关处于闭合位置时,电流能够流过断路器,为房间中的电灯、电视、电脑和其他设备供电。如果线路中出现故障,比如功率骤增,断路器就会打开,在电流损坏电子设备或房屋失火之前切断电流。

与之类似,软件中的断路器起初会处于关闭状态,允许进行方法的调用。如果因为某种原因,方法调用失败了(比如时间超出了定义的阈值),断路器就会打开,就不会对失败的方法再执行调用了。软件断路器的区别在于它提供了后备(fallback)行为和自校正功能。

如果被保护的方法在给定的失败阈值内发生了失败,那么可以调用一个后备方法代替它的位置。在断路器处于打开状态之后,几乎始终都会调用后备方法。处于打开状态的断路器偶尔会进入半开状态,并尝试调用发生失败的方法:如果依然失败,断路器就恢复为打开状态;如果调用成功,它会认为问题已经解决,断路器会回到闭合状态。图15.1阐述了软件断路器的流程。

image-20211023212429519

图15.1 断路器模式能够实现优雅的失败处理

按照我的阐述,断路器是应用到方法上的。这样,在给定的一个微服务中,很容易就能达到数十个(甚至更多)断路器。决定在代码的什么地方声明断路器其实就是识别哪些方法易于出现失败。如下的几类方法肯定是添加断路器的首选。

  • 调用REST的方法:这些方法可能会因为远程服务不可用或者返回HTTP 500响应而失败。
  • 执行数据库查询的方法:这些方法可能会因为数据库不响应或者模式变更破坏了应用而导致失败。
  • 可能会比较慢的方法:它们不一定会失败,但是如果耗费太长时间才能完成工作就可能会被视为失败。

最后一项强调了除处理故障之外断路器的另一项收益。在微服务中,延迟也是非常重要的,某个执行缓慢的微服务不能拖慢整个微服务的性能,避免上游的服务产生级联延迟是非常重要的。

我们可以看到,断路器模式是在代码中优雅处理故障和延迟的强大方法。那么该如何将断路器用到我们的代码中呢?幸运的是,Netflix开源项目通过Hystrix为我们提供了答案。

Netflix Hystrix是断路器模式的Java实现。简而言之,Hystrix断路器实现为一个切面,会在目标方法发生失败的时候触发后备方法。为了实现断路器模式,这个切面还会跟踪目标方法失败的频率;如果失败率超过了某个阈值,那么所有的请求都会转发至后备方法。

关于Hystrix名称的一点逸事

当Netflix的开发人员为他们的断路器实现起名字的时候,他们想要这个名字能够体现出需要提供的弹性、防御能力和容错能力。最终,他们选择了Hystrix(Hystrix是古代豪猪的一种,豪猪是一种能够使用长刺进行自卫的动物)。此外,正如Hystrix FAQ中所解释的,这是一个听起来很酷的名称。当我们在15.3.1小节中查看Hystrix dashboard时,我们就会在项目的Logo位置处看到一个豪猪的图案。

Spring Cloud Netflix包含对Hystrix的支持,提供了一个简单的编程模型。Spring和Spring Boot开发人员都应该很熟悉这个模型。为方法添加@HystrixCommand注解并提供一个后备方法,就可以为该方法声明断路器。下面让我们看看如何在Taco Cloud代码中声明断路器,从而优雅地使用Hystrix来处理失败。