首页 > 编程笔记

Spring Cloud Hystrix组件简介与使用

在微服务开发过程中,各个服务直接相互依赖是非常普遍的。当依赖的下游服务出现不可用时,为了防止整个调用链崩溃,可以进行熔断或者降级处理。Hystrix 就是 Netflix 公司开源的一款用于服务熔断或降级的工具。

Hystrix组件简介

Hystrix 是一款针对分布式系统的容错系统,旨在隔离依赖服务的访问,快速停止级联故障,让应用起到自我保护的作用。Hystrix 设计的主要目的如下:
  1. 为第三方依赖库提供保护。
  2. 停止级联故障。
  3. 快速失败。
  4. 回退并优雅地降级。
  5. 实现近实时的监控报警。

通常情况下的微服务系统如图 1 所示。

图1 微服务系统
图1 微服务系统

当某一个依赖项出现问题时,微服务系统如图 2 所示。

图2 某个依赖项出现问题时的微服务系统
图2 某个依赖项出现问题时的微服务系统

出现问题的依赖项导致阻塞,最终有可能引发雪崩,最终结果如图 3 所示。

图3 雪崩现象
图3 雪崩现象

针对以上问题,Hystrix是如何设计的呢?Hystrix遵循的设计原则如下:
  1. 阻止单个依赖项耗尽所有线程资源。
  2. 过载保护,立即熔断。
  3. 提供回退机制。
  4. 采用隔离技术。
  5. 近实时进行监控报警。
  6. 动态修改配置。
  7. 防止整个依赖执行失败。

为了实现以上目标,在 Hystrix 框架中实现了以下功能:

Hystrix原理

Hystrix的工作流程如下:
  1. 构造一个类继承HystrixCommand或HystrixObservableCommand,封装请求,重写方法。
  2. 执行命令,如果继承不同的Command类,则执行方法不同。
  3. 判断缓存是否开启,如果开启,则缓存响应。
  4. 判断熔断器是否开启,如果开启,则执行Fallback逻辑。
  5. 判断线程池是否已满,如果已满,则执行Fallback逻辑。
  6. 执行HystrixObservableCommand.construct()或HystrixCommand.run()方法,失败则执行Fallback逻辑。
  7. 统计熔断器的监控指标。
  8. 执行Fallback逻辑。
  9. 返回响应。

从以上流程中可以看到,Hystrix可以对分布式系统中的资源进行隔离,并快速熔断及降级。对于资源隔离,Hystrix 提供了两种隔离方式,即线程池隔离和信号量隔离。
  1. 线程池隔离:通过命令模式将不同业务的请求封装为相应的命令请求,然后为每一个命令配置一个线程池,通过将发送请求线程与执行请求的线程分离,有效防止级联故障。当线程池饱和时,直接执行 Fallback 逻辑。
  2. 信号量隔离:通过设置信号量来限制对某一个依赖项的并发调用。

线程池隔离与信号量隔离都有各自的优势,具体比较如表 4 所示。默认使用线程池隔离方式。

表4 线程池隔离与信号量隔离比较
表4 线程池隔离与信号量隔离比较

Hystrix 最主要的部分是熔断器设计,通过设置对应的参数值,在程序运行时达到设置的阈值后会开启熔断器。熔断器开启一段时间后,会对依赖服务进行试探,当依赖的服务恢复后,则放开流量,关闭熔断器。

不管是熔断器打开还是线程池已满,都会执行 Fallback 逻辑,Fallback 逻辑是一种降级措施。降级措施就是当微服务的依赖项不可用时,为了保证整体业务不受影响,可以支持返回一些备用的数据。

Hystrix示例

在 pom.xml 中引入 Hystrix 依赖的相关包,具体如下:
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard
</artifactId>
</dependency>
添加 @EnableCircuitBreaker 和 @EnableHystrixDashboard 注解,开启熔断器与 Dashboard 支持。

在 Controller 中添加测试方法,代码如下:
@GetMapping("/hystrix/test")
@HystrixCommand(fallbackMethod = "fallback")   //熔断处理
public String hystrixTest(String isFallback) {
   if (StringUtils.equals("1",isFallback)){
       throw new RuntimeException("fallback");
   } else {
       return "hystrix test!";
   }
}
public String fallback(String isFallback) {
     return "fallback!!";
}
经过测试可知,访问接口 http://localhost:8080/hi/hystrix/test?isFallback=0 时正常返回,访问接口 http://localhost:8080/hi/hystrix/test?isFallback=1时接口降级。

优秀文章