SpringCloud微服务系列 - Hystrix的使用和原理

SpringCloud微服务系列 - Hystrix的使用和原理

   概要

   Hystrix是Netflix开源的一款容错框架。集成到微服务体系里面的一个组件,是微服务体系里面的熔断器

   主要用于处理微服务架构中的故障,提供了一种机制来防止级联故障。在高并发访问下,系统所依赖的服务的稳定性对系统的影响非常大,依赖有很多不可控的因素,比如网络连接变慢,资源突然繁忙,暂时不可用,服务脱机等。我们要构建稳定、可靠的分布式系统,就必须要有这样一套容错方法。包含常用的容错方法:线程池隔离、信号量隔离、熔断、降级回退。

   一、熔断器

   Hystrix 采用了熔断器模式来保护系统免受持续失败的服务的影响。

   1.  熔断器的状态

   熔断器的状态分为三种:关闭、打开、半打开

   如下图:

   

   1)闭合(Closed)

   在这个状态下,熔断器允许所有请求通过,可以继续后续处理;

   2)打开(Open)

   当服务的失败率超过设定的阈值时,熔断器会进入打开状态。该状态下,该接口请求会被拦截,直接进行失败处理;在设定的休眠时间(默认是 5 秒)后,Hystrix 会进入半打开状态。

   3) 半打开(Half-Open)

   当熔断器打开一段时间后(默认是5秒),Hystrix会允许进行一次接口请求,当请求成功后,关闭熔断器,若请求失败,熔断器会再次进入打开状态,继续拒绝后续请求,并重新开始计时,直到达到下一个休眠时间。

   2. 熔断器的实现流程

   当熔断器的开关为关闭时,每次请求进来都是成功的,当后端服务出现问题,请求出现的错误数达到一定的阈值,则会触发断路器为打开状态,在断路器为打开状态时,进来的所有请求都会被拒绝,当然也不是一直会拒绝请求,而是弹性的,过了特定的时间后,断路器会进入半打开状态,这是会让一部分请求通过进行尝试,如果尝试还是有问题,则继续进入打开状态,并重新开始计时,直到达到下一个休眠时间。如果尝试没有问题了,则会进入关闭状态。

   3.  熔断器的打开条件

   1)请求总量达到阈值(默认是10秒内20个请求)

   在默认配置下,Hystrix 需要在一定时间窗口内收集到足够数量的请求。只有当请求数量达到这个阈值,后续的错误率才会被统计和评估

   2)错误率达到阈值(默认是10秒内错误率50%)

   在请求总量达到阈值的情况下,Hystrix 会计算错误率。如果在这个时间窗口内,错误请求的比例超过设定的阈值,那么熔断器将会打开。

   说明:以上这两个条件是协同工作的,只有当请求总量达到一定数目,且错误率超过设定阈值时,熔断器才会打开。因此,熔断器不会因为偶尔的错误或请求量过小而过早打开,这样可以提高系统的稳定性和可靠性。

   二、容错限流的原理

   对于基本的容错限流模式,主要有以下几点需要考量:

  • 主动超时:在调用依赖时尽快的超时,可以设置比较短的超时时间,比如2s,防止长时间的等待。
  • 限流:限制最大并发数。
  • 熔断:错误数达到阈值时,类似于保险丝熔断。
  • 隔离:隔离不同的依赖调用。
  • 服务降级:资源不足时进行服务降级。

   1. 服务降级

   当一个服务不可用时,Hystrix 允许定义降级方法。降级方法可以返回默认值或执行其他逻辑,以保证系统的可用性。

   触发场景:程序运行异常、超时、服务熔断触发服务降级、线程池/信号量满。

   2. 服务熔断

   依赖的下游服务多次在一定时间内故障达到了熔断阈值,为避免引发系统崩溃从而进行熔断(不再调用下游故障服务),熔断一定时间会自动尝试恢复。

   触发场景:n分钟内下游出现了m次故障

   3. 服务限流

   当集群处于高并发场景下为保证服务的可靠而进行限流操作

   4. 资源隔离

   Hystrix 通过线程池(threadpool)和信号量(semaphore)来隔离资源,确保关键任务的执行不会因为其他任务的故障而受到影响。

   1)线程池隔离

   Hystrix 为每个命令提供独立的线程池,确保某个命令的延迟或失败不会影响到其他命令的执行。这种方式适合于较重的操作,例如调用外部 API 或数据库。

   在Hystrix中,线程池隔离可以实现舱壁模式,确保不同服务调用的资源不会相互干扰,从而提高系统的容错能力和弹性。

@HystrixCommand(commandKey = "example", threadPoolKey = "exampleThreadPool")
public String remoteCall() {
    // 执行远程服务调用
}

   适用场景:

  • 高延迟的远程调用:当调用外部服务(如远程 HTTP、数据库查询等)可能会有较长的响应时间,且这些请求会占用较多的资源时。
  • 高并发场景:当服务需要处理大量并发请求时,线程池能够有效地限制并发量,避免过多的请求耗尽系统资源(如线程、CPU等)。

   2)信号量隔离

   对于轻量级操作(例如简单的数据库查询、缓存访问等),Hystrix 允许使用信号量来限制并发请求的数量,从而有效防止资源耗尽。

@HystrixCommand(commandKey = "example", semaphoreIsolation=true)
public String remoteCall() {
    // 执行快速操作
}

   信号量相当于一个计数器。初始化信号量currentCount=0,每进来一个请求需要先将currentCount自增,再判断currentCount的值是否小于系统最大信号量,小于则继续执行,大于则直接返回,拒绝请求。

   适用场景:

  • 轻量级、低延迟的操作:对于不需要独立线程池的轻量级操作(例如简单的数据库查询、缓存访问等),信号量可以通过限制请求数量来有效隔离。
  • 短时间内的高并发请求:如果某些请求非常短小且不会占用太多资源,使用信号量可以节省系统开销,避免不必要的线程创建。

   说明:默认情况下,Hystrix 使用线程池隔离 (THREAD),即每个命令都会使用一个独立的线程池来执行。  

   三、Hystrix 使用

   1. 添加依赖

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

   2. 主启动类

1 @SpringBootApplication
2 @EnableHystrix
3 public class PaymentApplication8007 {
4 
5     public static void main(String[] args) {
6        SpringApplication.run(PaymentApplication8007.class);
7     }
8 }

   3. 如果服务消费端使用需要再application.properties进行配置

feign:
  hystrix:
   enabled: true

   这将确保 Hystrix 功能应用于所有 Feign 调用。

   4. 定义熔断策略

   使用@HystrixCommand注解定义服务调用的熔断策略。通过配置Hystrix的参数,可以详细控制断路器的行为,如超时时间、请求阈值等

 1 /**服务提供者模拟请求处理超时,服务消费者通过dystr1x控制*/
 2 //使用HystrixCommand注解进行熔断控制
 3 @HystrixCommand(
 4    //将相关的 Hystrix 命令进行分组,以便于管理和监控
 5    groupKey = "ProductGroup",
 6 
 7    //线程池标识配置,默认情况下所有的请求共同维护一个线程池
 8    threadPoolKey="findProductServerPort",
 9 
10    //线程池细节属性配置
11    threadPoolProperties = {
12       //核心线程为2
13       @HystrixProperty(name="coresize",value="20"),
14       //等待队列的最大长度
15       @HystrixProperty(name="maxQueueSize",value="20")
16    },
17 
18    //配置Hystrix熔断器的属性信息
19     commandProperties = {
20        //设置请求的超时时间,一旦超过配置的时间会触发Hystrix的处理机制
21        @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
22        //Hystrix高级配置,定制工作过程细节
23        //统计时间窗口定义
24        @HystrixProperty(name="metrics.rollingstats.timeInMilliseconds",value="10000"),
25        //统计时间窗口内的最小请求数
26        @HystrixProperty(name="circuitBreaker.requestvolumeThreshold",value="20"),
27        //统计时间窗口内的错误数量百分比阈值。
28        @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value="50"),
29        //自我修复时的活动窗口长度
30        @HystrixProperty(name="circuitBreaker.sleepwindowInMilliseconds",value="5000")
31     }
32 
33     //表示回退方法。如果对应的服务提供者出现问题,则会调用FallbackMethod属性所指向的方法,将该方法的返回值作为最终响应给客户端的数据
34     fallbackMethod="getProductServerPortFallbackMethod"
35 
36 37     @GetMapping("timeout")
38     public CompletableFuture<String> timeout() {
//...
39 } 40 41 public String getProductServerPortFallbackMethod(){ 43 return "超时啦"; 44 }

   @HystrixCommand 注解是 Hystrix 提供的一个非常重要的功能,用于简化对外部服务调用的管理和容错处理

   注意:

   1.  @HystrixCommand是加在服务消费者对应的方法上的。

   2.  HystrixCommand 和 HystrixObservableCommand

    HystrixCommand 和 HystrixObservableCommand这两个类是 Hystrix 命令模式的核心实现。HystrixCommand 用于同步执行命令,而 HystrixObservableCommand 用于异步执行。

   3. HystrixPropertiesManager

   Hystrix参数不用我们刻意去记下,可以根据HystrixPropertiesManager这个类去查看。

   四、版本支持

   Spring Cloud 2021.0.x 版本之后,Netflix Hystrix 已经被完全移除,不再被官方维护和支持。这意味着在 Spring Cloud 2021 及更高版本中,Hystrix 相关的依赖将无法自动解析。

   在这种情况下,建议的方案是迁移到 Spring Cloud 提供的替代方案 Resilience4j。Resilience4j 提供了与 Hystrix 类似的断路器、限流、重试等功能,并且更适合与 Spring Cloud 2021 及以后的版本搭配使用。

   如果确实需要使用 Hystrix,可以尝试以下方式:

   1)降级到 Spring Cloud 2020.x 版本:如果可以,降级到支持 Hystrix 的最后一个稳定版本 Spring Cloud Hoxton(2020.x 系列)。

   2)手动引入 Hystrix:如果必须在 2021 版本中使用 Hystrix,可以尝试手动指定 Hystrix 的版本,但需要注意兼容性问题。Hystrix 的最后一个版本是 1.5.18:

<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-core</artifactId>
    <version>1.5.18</version>
</dependency>

   更推荐的做法是迁移到 Resilience4j,以便获得更好的支持和兼容性。

   五、总结

   1. Hystrix 通过这些核心类和接口实现了断路器模式,提供了线程池隔离、请求缓存、服务降级等功能。

   2. 每个命令在执行时都会被封装为一个 HystrixCommand 实例,并在一个独立的线程池中执行。CircuitBreaker 根据 HystrixCommandMetrics 提供的度量数据来决定是否跳闸。这些组件协同工作,确保了分布式系统在面对服务故障和延迟时的健壮性和弹性。

   3. 熔断器是加在调用者端的,目的是保护系统免受被调用服务出现问题而引发的连锁故障。它可以检测服务健康状况并控制请求流量,以确保系统能够保持弹性,避免因某个服务的故障而导致整个系统崩溃。

 

   参考链接:

   https://juejin.cn/post/7359464203357437978

posted @ 2024-11-04 19:06  欢乐豆123  阅读(6)  评论(0编辑  收藏  举报