Hystrix使用及原理概述

本文介绍了Netflix开源的容错库Hystrix,它用于处理分布式系统中的故障和延迟。阐述了Hystrix的背景、目标、功能,详细讲解其执行流程、断路器工作流程和隔离策略,还介绍了在原生及Spring Cloud中的使用方法、参数配置和常见模式,以提高系统可用性和稳定性。

一、背景

1. 当前问题

一个系统,所有请求共用同一个APP容器(Tomcat/jetty/等),共用一个用户线程池,依赖多个不同的远程服务。

当系统健康时,处理请求的延时较低,服务正常运行;当某个后端依赖项变得延迟,会导致处理该请求的用户线程长时间阻塞。在流量较低时,只会影响请求本身;在高流量的情况下,单个后端依赖项的延迟可能会导致服务的所有用户线程都在阻塞等待。

这个问题不仅导致与该后端依赖项有关的请求没办法被正常处理,还会导致其他请求拿不到所需资源而出现异常,从而导致整个系统都没办法正常运行。

对于上述问题,需要通过手段对故障、延迟进行隔离和管理,以便单个失败的依赖项不会导致整个应用程序或系统崩溃。
soa-1-original.png

soa-2-original.png

soa-3-original.png

2. Hystrix简介

Hystrix是Netflix开源的容错库,旨在处理分布式系统中的故障和延迟。它通过实现断路器模式、请求缓存、请求合并等功能,提供了弹性和可靠的解决方案。Hystrix能够在服务之间进行隔离,当一个服务出现故障时,它可以防止故障的扩散,提高系统的可用性和稳定性。在微服务架构中,一个请求需要调用多个服务是非常常见的,较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阈值(Hystrix是5秒20次)断路器将会被打开。断路打开后,可以避免连锁故障,通过fallback方法快速返回一个值。

3. Hystrix的目标

Hystrix旨在实现以下目标:

  • 保护并控制通过第三方客户端库访问(通常是通过网络)的依赖项的延迟和故障。
  • 阻止复杂分布式系统中的级联故障。
  • 快速失败并快速恢复。
  • 在可能的情况下回退并优雅降级。
  • 启用近乎实时的监控、警报和操作控制。

4. Hystrix的功能

为了实现上述目标,Hystrix提供了以下功能:

  • HystrixCommandHystrixObservableCommand对象包装对所有外部系统(或“依赖项”)的调用,通常在单独的线程中执行
  • 自定义调用依赖项的超时时间
  • 为每个依赖项维护一个小的线程池(或信号量);如果它变满,将要发送到该依赖项的请求立即被拒绝,而不是排队等待
  • 统计成功、失败(客户端抛出的异常)、超时和线程拒绝的数量
  • 可通过手动或自动的方式,开启断路器以停止一段时间内对特定服务的所有请求;当统计的失败率超过阈值,断路器会自动开启
  • 在请求失败、被拒绝、超时或短路时执行fallback逻辑
  • 近实时地监控指标和配置更改

soa-4-isolation-original.png

二、原理介绍

1. Hystrix执行流程

下图展示了通过Hystrix请求远程服务的流程

hystrix-command-flow-chart.png

1.1 创建HystrixCommand/HystrixObservableCommand对象

第1步,创建一个HystrixCommandHystrixObservableCommand包装远程调用依赖的过程。HystrixCommandHystrixObservableCommand的区别后续介绍。

1.2 执行Command

第2步,执行第一步创建的命令Command,可以使用以下四种方式:execute()queue()observe()toObservable(),区别后续介绍

1.3 判断是否有请求缓存

第3步,判断是否有请求缓存,若存在请求缓存则直接将缓存的值返回,请求缓存的用法后续介绍。

1.4 判断是否开启断路

第4步,判断断路器是否开启,开启则不能执行远程调用的操作,直接到第8步;若未开启,则到第5步。第4步的断路器开启与否,是通过第7步的断路器健康值判断的。

1.5 判断线程池/信号量是否已满

第5步,如果与命令关联的线程池和队列(或信号量)已满,那么Hystrix将不会执行该命令,而是立即将流量路由到(8)获取Fallback。第5步的结果会反馈到第7步的断路器健康值中。

1.6 执行远程调用

第6步,执行远程调用的方法。在第1步构造的HystrixCommandHystrixObservableCommand中,会重写HystrixCommand.run()HystrixObservableCommand.construct(),里面执行远程调用过程。

如果执行失败/超时,则会路由到第8步执行fallback方法。

值得注意的是,执行超时时,线程隔离策略下定时器会抛出超时异常,并且通知执行任务的线程中断;信号量隔离策略下,定时器会抛出超时异常,但是执行任务的线程会执行到任务结束。

1.7 计算断路器的健康度

第7步,Hystrix向断路器报告成功、失败、拒绝和超时,断路器维护一组滚动计数器来计算统计数据。

它使用这些统计数据来确定何时应该断路,此时它会拒绝任何后续请求,直到恢复期过去,然后它会让会进入半开状态。在此状态下,下一个请求将尝试调用后端服务。如果该请求成功,断路器会认为服务已经恢复并转回 关闭 状态;如果请求仍然失败,断路器会再次回到 打开 状态,继续进行短路操作。

1.8 获取并执行fallback

第8步,当第4步发现断路器打开、第5步线程池/信号量已满、第6步执行异常/超时,Hystrix就会尝试获取Command中自定义的备用方法getFallback()。建议该方法不依赖任何网络连接,而是从内存缓存或其他静态逻辑中获取。

如果fallback执行异常或者没有重写getFallback()方法,则会抛出异常。

1.9 返回成功的响应

如果执行成功,则会将远程调用的结果返回给调用者。

2. 断路器工作流程

下图展示了HystrixCommand和断路器的交互流程以及断路器的工作流程:

  1. 当执行HystrixCommand时,会调用断路器查询是否允许请求。断路器会查询断路器是否开启,若没开启,直接返回允许请求;若断路器已开启,会判断恢复时间是否已过,已过允许1个请求,未过返回不允许请求。(对应2.1的第4步)
  2. 判断断路器是否开启的方式时,计算时间范围内错误百分比是否超过阈值,如果超过阈值,则返回已开启。
  3. 当执行HystrixCommand之后,会将结果反馈给断路器,以更新断路器的健康度。

circuit-breaker-original.png

3、 隔离策略

Hystrix 使用舱壁模式来隔离依赖关系,并限制对任何单一依赖关系的并发访问。

soa-5-isolation-focused-original.png

3.1 线程池隔离(THREAD)

在此策略中,每个服务调用都在独立的线程中执行。线程隔离可以防止服务调用时间过长,导致其他服务调用受到影响。当一个服务调用超时或发生故障时,它不会影响到其他服务调用。线程隔离可以确保服务之间的独立性,提高系统的稳定性。

request-example-with-latency-640.png

isolation-options-640.png

3.1.1 优势
  • 该应用程序完全不受失控客户端库的影响。给定依赖库的池可以填满,而不会影响应用程序的其余部分。
  • 支持任务排队
  • 支持超时中断
  • 支持异步调用
3.1.2 劣势
  • 线程调用会产生额外的开销
3.1.3 适用场景
  • 对于可能耗时较长、网络延迟较高的外部服务调用。
  • 当需要确保每个命令在独立的线程上运行以防止阻塞主线程。
  • 为了防止故障传播和资源耗尽,需要对每个命令进行严格的资源限制。
  • 能够承受一定的线程创建和销毁的开销,以换取更稳定的系统行为。
  • 适用于处理高负载和突发流量的情况,因为线程池可以帮助稳定系统的整体性能。

3.2 信号量隔离(SEMAPHORE)

信号量隔离是一种基于计数器的轻量级隔离方法,它不创建新的线程。相反,Hystrix 使用一个指定大小的信号量来控制并发访问的数量。一旦达到最大值,任何额外的请求都将被拒绝并触发降级策略。

3.2.1 优势
  • 轻量,无额外开销
3.2.2 劣势
  • 不支持任务排队
  • 不支持超时中断。执行超时,执行线程会继续阻塞,直到底层的网络调用超时
  • 不支持异步调用。实际上还是所有请求共用用户线程,没办法完全隔离。
3.2.3 适用场景
  • 对性能敏感或低延迟要求的应用。
  • 当调用的服务通常是快速响应的,例如查询缓存服务或者内部服务间通信。
  • 调用的依赖服务不需要消耗大量的 CPU 或者 IO 资源。
  • 需要严格控制并发请求的数量,但又不希望引入额外的线程开销。
  • 在某些情况下,可以用于轻量级的微服务之间的一致性保证。

三. 使用介绍

本章节将介绍hystrix提供的原始API、Spring Cloud集成Hystrix的使用

1. Hystrix使用

1.1 依赖

<!-- https://mvnrepository.com/artifact/com.netflix.hystrix/hystrix-core -->
<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-core</artifactId>
    <version>1.5.18</version>
</dependency>

1.2 Hello World

下面是创建一个HystrixCommand的方式,继承HystrixCommand,泛型为远程调用响应的类型。

构造方法中指定了该命令所属的分组key,Hystrix会基于分组key用于报告、告警、仪表盘、权限控制等,并且在不指定线程池的情况下,会根据这个key命名线程池。(也就是说,相同key共用同一个线程池)

run()方法中,是真正执行远程调用的位置。

public class CommandHelloWorld extends HystrixCommand<String> {
   
   

    private final String name;

    public CommandHelloWorld(String name) {
   
   
        // 指定命令分组为ExampleGroup
        super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
        this.name = name;
    }

    @Override
    protected String run() {
   
   
        // 真正执行远程调用的位置
        return "Hello " + name + "!";
    }
}

执行HystrixCommand,同步等待结果

String s = new CommandHelloWorld("World").execute();

执行HystrixCommand,异步等待结果。

Future<String> fs = new CommandHelloWorld("World").queue();
String s = fs.get();

响应式执行HystrixCommandobserve()HystrixCommand转换为Observable,并通过subscribe()设置订阅者,设置当处理结果、处理异常、出现新元素时的行为。

Observable<String> ho = new CommandHelloWorld("World").observe();
ho.subscribe(new Subscriber<String>() {
   
   
    @Override
    public void onCompleted() {
   
   
        LOGGER.info("Completed.");
    }
    @Override
    public void onError
03-10
### Hystrix 使用指南 #### 启用 Feign 和 Hystrix 支持 为了使Feign客户端能够利用Hystrix的功能,在`application.yml`或者`application.properties`文件里需要设置特定参数以激活此功能。对于YAML格式的配置文件而言,应当加入如下所示的内容: ```yaml feign: hystrix: enabled: true # 开启 feign 对 hystrix 的支持[^1] ``` 这一步骤确保了每当通过Feign发起远程调用的时候,默认情况下都会被包裹在一个Hystrix命令之中。 #### 配置熔断器属性 进一步定制化Hystrix行为可以通过调整一系列与之关联的选项实现。下面是一些常用的配置项及其含义说明: - `execution.isolation.thread.timeoutInMilliseconds`: 设置线程隔离模式下执行超时时间(毫秒),超过该时限则认为操作失败并触发回退逻辑; - `circuitBreaker.requestVolumeThreshold`: 定义触发熔断前最小请求数量阈值;一旦达到这个数目并且错误率超过了设定比例,则启动熔断机制; - `circuitBreaker.errorThresholdPercentage`: 错误百分比门限值,即当一段时间内的请求中有多少比例发生异常才会考虑开启熔断开关; - `circuitBreaker.sleepWindowInMilliseconds`: 半开状态持续的时间长度,在这段时间过后允许一定数量的新请求试探性地访问目标服务,以此判断后者是否已经恢复正常运作。 具体应用到配置文件中可以写作: ```yaml hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 2000 # 超时时间为2秒钟 circuitBreaker: requestVolumeThreshold: 10 # 请求次数达到10次作为评估依据 errorThresholdPercentage: 50 # 如果一半以上的请求失败就会跳闸 sleepWindowInMilliseconds: 5000 # 断路器保持关闭等待期为5秒后再试 ``` 上述配置使得系统能够在遇到频繁故障的情况下迅速做出反应,并给予适当缓冲以便于自我修复过程的发生[^2]。 #### 工作原理概述 Hystrix的工作方式类似于现实生活中的保险丝装置——它监控着各个Command对象所代表的操作流程,并收集有关成功率/失败率等相关统计数据。基于这些数据,Hystrix决定何时应该“烧毁”连接至下游系统的通路以防止单点失效引发更大范围的影响。而所谓的“熔断”,实际上是指停止向已知存在问题的目标发送新的请求直到确认对方重新变得可靠为止。在此期间,任何试图穿越已被切断路径的动作都将立即返回预定义好的备用响应而非真正去尝试建立联系。经过一段指定间隔之后,Hystrix会谨慎地释放少量资源给潜在可恢复的服务端口做测试用途,从而动态监测其健康状况。倘若验证无误,则正式解除限制措施让一切回归常态[^3]。 #### 微服务体系下的重要角色 考虑到当今分布式环境中各组件间紧密协作的特点以及由此带来的连锁风险隐患,像Hystrix这样专注于解决此类问题的技术方案显得尤为重要。尤其是在面对那些具有高度不确定性的外部依赖关系时,合理运用诸如熔断、降级等策略可以帮助我们构建更加稳健的应用程序架构,有效防止因个别环节失灵而导致全局瘫痪的局面出现[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值