一、Hystrix是什么

Hystrix是由Netflix开源的一个服务隔离组件,通过服务隔离来避免由于依赖延迟、异常,引起资源耗尽导致系统不可用的解决方案。
在分布式系统,我们一定会依赖各种服务,那么这些个服务一定会出现失败的情况,Hystrix就是这样的一个工具,它通过提供了逻辑上延时和错误容忍的解决力来协助我们完成分布式系统的交互。Hystrix 通过分离服务的调用点,阻止错误在各个系统的传播,并且提供了错误回调机制,这一系列的措施提高了系统的整体服务弹性。
分布式系统环境中,服务间类似依赖非常常见,一个业余调用通常依赖多个基础服务。如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。并且这种不可用可能沿请求调用链向上传递,这种现象称为雪崩效应。
image.png
SpringCloud的限流、降级和熔断——Hystrix

Hystrix 的历史

Hystrix 是2011 从Netflix API 团队发展而来。 2012 Hystrix持续发展并且成熟,并且有非常多的团队开始采用Hystrix.现在在Netflix每天有数十万的线程,数百万的独立信号量通过Hystrix执行,这几大增强了服务的弹性和服务时间。

Hystrix 是干嘛的

Hystrix 被设计用来做了下面几件事:

  • 保护系统间的调用延时以及错误,特别是通过第三方的工具的网络调用
  • 阻止错误在分布式系统之前的传播
  • 快速失败和迅速恢复
  • 错误回退和优雅的服务降级

    Hystrix 解决了什么问题

    应用在复杂的分布式系统中存在非常多的依赖,这其中一些服务不可避免的会失败,如果主应用程序没有和依赖的服务隔离开来,那么它的服务成功率就会下降
    举个例子, 一个服务依赖30个不同的服务,每个服务的服务成功率为99.99%,这个服务的成功率就可以这样计算:
    99.99*99.99。。。。。30 = 99.7 这样算来 1000个请求中就有3个是失败的, 这样一来 每个月基本上会有差不多2个小时的停机时间
    这只是一个计算值,现实情况可以比这个更糟糕。
    尽管我们我们可以将每个服务的成功率再往上提升,比如现在没1万个请求才会失败一个,但是还是任然每个月了数小时的停机,
    13:Hystrix服务熔断 - 图2

13:Hystrix服务熔断 - 图3
在应用程序中,每一个通过网络或者使用第三方客户端发送出去的请求都有可能会失败,比失败更糟糕的是,这会增加服务间的调用延时。
上面的这些问题会变得更加的严重,当我们通过第三方客户端发送网络请求,因为第三方客户端对于我们而言是“黑盒”,并且它的实现是随时可能改变的。并且每一个客户端的资源配置都是不同的,这样就非常的难监控和改变。
……
网络连接失败或者降级,服务或者服务机器停机或者变慢,新的客户端或者部署的新的服务改变了原有的行为,亦或者客户端有bugs。
上面的所有错误形式都需要被单独隔离出来,这样不至于一个简单的错误导致整个系统的失败。

Hystrix 的设计原则是什么

Hystrix工作方式如下:

  • 阻止一个单独的依赖耗尽系统的所有线程,比如(tomcat)
  • 使用快速失败代替将这个请求排队
  • 在任何可能失败的地方提供后退机制来确保用户不会看到错误
  • 使用隔离技术(比如:隔板,泳道,环路切断 模式)降低一个依赖的失败对整个系统的影响
  • 优化使得系统可以近乎实时的收集,监控,报警
  • 优化使得系统可以近乎实时的修改,并且可以近乎实时生效
  • 保护系统不仅仅在网络层面,也包括客户端层面的依赖执行的失败

    Hystrix 是怎样的实现这些目标

    Hystrix 通过如下的方式实现了这些目标:

  • 通过使用命令模式包装所有的调用外部系统的请求,这些个请求都单独的运行在不同的线程中,在Hystrix中主要通过 “HystirxCommand”,”HystixObservableCommand”实现

  • 调用超时比我们自定义的超时时间更久,所以我们在使用的过程中最好自定义网络调用的超时时间,在Hystrix中,提供了配置可以修改默认的超时时间,那么超时间到底应该定义为多少? 就一般经验值而言,设置为服务成功率为99.5%时的平均时间
  • 每一个服务都维护着一个小的线程池或者信号量,一旦线程池或者信号量饱和了,那么采取的策略是拒绝请求而不是将请求排队
  • 记录成功,失败,超时,线程拒绝数据
  • 提供一个回调接口,当一个请求失败,或者被拒绝,超时亦或者因为短路而拒绝
  • 监控系统运行数据并且可以近乎实时的修改系统配置
  • 一段时间内当短路发生时,拒绝所有的请求,或者当错误率超过了阀值

当你使用Hystrix包装所有的依赖时,系统的整体架构和上面的那张图差不多一致的,每一个依赖之间都是相互隔离的,这样可以为每一服务提供失败回滚逻辑等等。

主要有3种解决方案

  • (1) 熔断模式:
    这种模式主要是参考电路熔断,如果一条线路电压过高,保险丝会熔断,防止火灾。放到我们的系统中,如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。
  • (2) 隔离模式:这种模式就像对系统请求按类型划分成一个个小岛的一样,当某个小岛被火烧光了,不会影响到其他的小岛。例如可以对不同类型的请求使用线程池来资源隔离,每种类型的请求互不影响,如果一种类型的请求线程资源耗尽,则对后续的该类型请求直接返回,不再调用后续资源。这种模式使用场景非常多,例如将一个服务拆开,对于重要的服务使用单独服务器来部署,再或者公司最近推广的多中心。
  • (3)限流模式:上述的熔断模式和隔离模式都属于出错后的容错处理机制,而限流模式则可以称为预防模式。限流模式主要是提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源。这种模式不能解决服务依赖的问题,只能解决系统整体资源分配问题,因为没有被限流的请求依然有可能造成雪崩效应。

    熔断设计

    在熔断的设计主要参考了hystrix的做法。其中最重要的是三个模块:熔断请求判断算法、熔断恢复机制、熔断报警

  • (1)熔断请求判断机制算法:
    使用无锁循环队列计数,每个熔断器默认维护10个bucket,每1秒一个bucket,每个blucket记录请求的成功、失败、超时、拒绝的状态,默认错误超过50%且10秒内超过20个请求进行中断拦截。

  • (2)熔断恢复:
    对于被熔断的请求,每隔5s允许部分请求通过,若请求都是健康的(RT<250ms)则对请求健康恢复。
  • (3)熔断报警:
    对于熔断的请求打日志,异常请求超过某些设定则报警

    隔离设计

    隔离的方式一般使用两种:
    (1)线程池隔离模式:使用一个线程池来存储当前的请求,线程池对请求作处理,设置任务返回处理超时时间,堆积的请求堆积入线程池队列。这种方式需要为每个依赖的服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据存储到线程池队里慢慢处理)。
    (2)信号量隔离模式:使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,请求来先判断计数器的数值,若超过设置的最大线程个数则丢弃改类型的新请求,若不超过则执行计数操作请求来计数器+1,请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流量洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)。

    二、雪崩效应

    1、常见场景

  1. 硬件故障:如服务器宕机,机房断电,光纤被挖断等。
  2. 流量激增:如异常流量,重试加大流量等。
  3. 缓存穿透:一般发生在应用重启,所有缓存失效时,以及短时间内大量缓存失效时。大量的缓存不命中,使请求直击后端服务,造成服务提供者超负荷运行,引起服务不可用。
  4. 程序bug:如程序逻辑导致内存泄漏,JVM长时间FullGC等。
  5. 同步等待:服务间采用同步调用模式,同步等待造成的资源耗尽。

    2、应对策略

    针对造成雪崩效应的不同场景,可以使用不同的应对策略,没有一种通用所有场景的策略。

  6. 硬件故障:多机房容灾、异地多活等。

  7. 流量激增:服务自动扩容、流量控制(限流、关闭重试)等。
  8. 缓存穿透:缓存预加载、缓存异步加载等。
  9. 程序bug:修改程序bug、及时释放资源等。
  10. 同步等待:资源隔离、MQ解耦。、不可用服务调用快速失败等。资源隔离通常指不同服务调用采取不同的线程池;不可用服务调用快速失败一般通过熔断模式结合超时机制实现。

综上所述,如果一个应用不能对来自依赖的故障进行隔离,那该应用本身就处在被拖垮的风险中。因此,为了构建稳定、可靠的分布式系统,我们的服务应当具有自我保护能力,当依赖服务不可用时,当前服务启动自我保护功能,从而避免发生雪崩效应。本文将重点介绍使用Hystrix解决同步等待的雪崩问题。

三、初探Hystrix

Hystrix,中文含义是豪猪,因其背上长满荆棘,从而拥有了自我保护的能力。本文所说的Hystrix是Netflix公司开源的一款容错框架,同样具有自我保护能力。为了实现容错和自我保护,下面我们看看Hystrix如何设计和实现的。

Hystrix设计目标

  • 对来自依赖的延迟和故障进行防护和控制,这些依赖通常都是通过网络访问的。
  • 阻止失败并迅速恢复
  • 回退并优雅降级
  • 提供近实时的监控与告警

    Hystrix遵循的设计原则

  • 防止任何单独的依赖耗尽资源(线程)

  • 过载立即切断并快速失败,防止排队
  • 尽可能提供回退以保护用户免受故障
  • 使用隔离技术(例如隔板、泳道和断路器模式)来限制任何一个依赖的影响
  • 通过近实时的指标,监控和告警,确保故障被及时发现
  • 通过动态修改配置属性,确保故障及时恢复
  • 防止整个依赖客户端执行失败,而不仅仅是网络通信

    Hystrix如何实现这些设计目标

  • 使用命令模式将所有对外部服务(或依赖关系)的调用包装在HystrixCommand或 HystrixObservableCommand对象中,并将该对象放在单独的线程中执行。

  • 每个依赖都维护着一个线程池(或信号量),线程池被耗尽则拒绝请求(而不是让请求排队)。
  • 记录请求成功,失败,超时和线程拒绝。
  • 服务错误百分比超过了阈值,熔断器开关自动打开,一段时间内停止对该服务的所有请求。
  • 请求失败,被拒绝,超时或熔断时执行降级逻辑。
  • 近实时地监控指标和配置的修改。

    四、Hystrix处理流程

    image.png

    Hystrix 整个工作流程如下

    构造一个 HystrixCommand或HystrixObservableCommand对象, 用于封装请求,并在构造方法配置请求被执行需要的参数;
  1. 执行命令, Hystrix 提供了4种执行命令的方法,后面详述;
  2. 判断是否使用缓存响应请求,若启用了缓存,且缓存可用,直接使用缓存响应请求。 Hystrix 支持请求缓存,但需要用户自定义启动;
  3. 判断熔断器是否打开,如果打开,调到第8步;
  4. 判断线程池、队列、信号量是否已满,已满则调到第8步;
  5. 执行 HystrixObservableCommand.construct()或HystrixCommand.run(), 如果执行失败或者超时,跳到第8步;否者,跳到第9步;
  6. 统计熔断器监控指标;
  7. 走Fallback降级方法;
  8. 返回请求响应。

从流程图上可知道,第5步线程池、队列、信号量已满时,还会执行第7步逻辑,更新熔断器统计信息,而第6步无论成功与否,都会更新熔断器统计信息。

执行命令的几种方法

Hystrix提供了4种执行命令的方法,execute()和queue()适用于 HystrixCommand 对象,而observer()和toObservable()适用于 HystrixObservableCommand对象。

1、execute()

以同步阻塞方法执行run(),只支持接收一个值对象。 Hystrix会从线程池中取一个线程来执行run(),并等待返回值。

2、queue()

以异步非阻塞方法执行run(),只支持接收一个值对象。调用queue()就直接返回一个Future对象。可通过Future.get()拿到run()的返回结果,但 Future.get() 是阻塞执行的。若执行成功, Future.get() 返回单个返回值。当执行失败时,如果没有重写fallback, Future.get() 抛出异常。

3、observe()

事件注册前执行run()/construct(),支持接收多个值对象,取决于发射源。调用observe()会返回一个hot Observable,也就是说,调用 observe()自动触发执行run()/construct(),无论是否存在订阅者。
如果继承的是HystrixCommand,hystrix会从线程池中取一个线程以非阻塞方式执行run();如果继承的是HystrixObservableCommand,将以调用线程阻塞执行construct()。
observe()使用方法

  1. 调用 observe()会返回一个Observable对象
  2. 调用这个 Observable对象的subscribe()方法完成事件注册,从而获取结果

    4、toObservable()

    事件注册后执行run()/construct(),支持接收多个值对象,取决于发射源。调用 toObservable() 会返回一个cold Observable,也就是说,调用 toObservable() 不会立即触发执行run()/construct(),必须有订阅者订阅 Observable 时才会执行。
    如果继承的是 HystrixComman,hystrix会从线程池中取一个线程以非阻塞方式执行run(),调用线程不必等待run();如果继承的是 HystrixObservableCommand ,将以调用线程堵塞执行construct(),调用线程需等待construct()执行完才能继续往下走。
    toObservable()使用方法

  3. 调用observe()会返回一个Observable对象

  4. 调用这个 Observable对象的subscribe()方法完成事件注册,从而获取结果

需注意的是, HystrixCommand也支持 toObservable()和observe(), 但是即使将 HystrixCommand 转换成Observable,它也只能发射一个值对象。只有 HystrixObservableCommand才支持发射多个值对象。

几种方法的关系

image.png

  • execute()实际是调用了queue().get()
  • queue()实际调用了toObservable().toBlocking().toFuture()
  • observe()实际调用toObservable()获得一个cold Observable,再创建一个ReplaySubject对象订阅Observable,将源Observable转化为hot Observable。因此调用observe()会自动触发执行run()/construct()。

Hystrix 总是以Observable的形式作为相应返回,不同执行命令的方法只是进行了相应的转换。

五、 Hystrix 容错

Hystrix 的容错主要是通过添加容许延迟和容错方法,帮助控制这些分布式服务之间的交互。还通过隔离服务之间的访问点,阻止它们之间的级联故障以及提供退回选项来实现这一点,从而提高系统的整体弹性。 Hystrix主要提供了一下几种容错方法:

  • 资源隔离

  • 熔断

  • 降级


  • 资源熔断

    资源隔离主要指对线程的隔离。 Hystrix提供了两种线程隔离的方式:线程池和信号量。

    1、线程隔离-线程池

    Hystrix还通过命令模式对发送请求的对象和执行请求的对象进行解耦,将不同类型的业务请求封装为对应的命令请求。如订单服务查询商品,查询商品请求->商品command;商品服务查询库存,查询库存请求->库存command。并且为每个类型的command配置一个线程池,当第一次创建command时,根据配置创建一个线程池,并放入ConcurrentHashMap,如商品command:

    1. final static ConcurrentHashMap<String, HystrixThreadPool> threadPools = new ConcurrentHashMap<String, HystrixThreadPool>();...if(!threadPools.containsKey(key))
    2. {
    3. threadPools.put(key, new HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder));
    4. }

    后续查询商品的请求创建command时,将会重用已创建的线程池。线程池隔离之后的服务依赖关系:
    image.png
    通过发送请求线程与执行请求的线程分离,可有效防止发生级联故障。当线程池或请求队列饱和时,Hystrix将拒绝服务,使得请求线程可以快速失败,从而避免依赖问题扩散。
    线程池隔离优点:

  • 保护应用程序以免受来自依赖故障的影响,指定依赖线程池饱和不会影响应用程序的其余部分。

  • 当引入新客户端lib时,即使发生问题,也是在lib中,并不会影响其他内容。
  • 当依赖从故障恢复正常时,应用程序会立即恢复正常的性能。
  • 当应用程序一些配置参数错误时,线程池的运行状况会很快检测到这一点(通过增加错误、延迟、超时、拒绝等),同时可以通过动态属性进行实时纠正错误的参数配置。
  • 如果服务的性能有变化,需要实时调整,比如增加或减少超时时间,更改重试次数,可以通过线程池指标状态属性修改,而且不会影响到其它调用请求。
  • 除了隔离优势外, Hystrix 拥有专门的线程可提供内置的并发功能,使得可以在同步调用之上构建异步门面(外观模式),为异步编程提供了支持( Hystrix 引入了R小Java异步框架)。
  • 注意:尽管线程池提供了线程隔离,我们的客户端底层代码也必须要有超时设置或响应线程中断,不能无限制的阻塞以致线程池一直饱和。

缺点:
线程池的主要缺点是增加了计算开销。每个命令的执行都在单独的线程完成,增加了排队、调度和上下文切换的开销。因此,要使用 Hystrix ,就必须接受它带来的开销,以换取它所提供的的好处。
通常情况下,线程池引入的开销足够小,不会有重大的成本和性能影响。但对于一些访问延迟极低的服务,如只依赖内存缓存,线程池引入的开销就比较明显了,这时候使用线程池隔离技术就不合适了,我们需要考虑更轻量级的方式,如信号量隔离。

2、线程隔离-信号量

线程池隔离的缺点,当依赖延迟极低的服务时,线程池隔离技术引入的开销超过了它所带来的好处。这时候可以使用信号量隔离技术来代替,通过设置信号量来限制对任何给定依赖的并发调用量。下图说明了线程池隔离和信号量隔离的主要区别:
image.png
使用线程池时,发送请求的线程和执行依赖服务的线程不是同一个,而使用信号量时,发送请求的线程和执行依赖服务的线程时同一个, 都是发起请求的线程。

3、线程隔离总结

线程池和信号量都可以做线程隔离,但各有各的优缺点和支持的场景,对比如下:
线程切换支持异步支持超时支持熔断限流开销信号量否否否是是小线程池是是是是是大
线程池和信号量都支持熔断和限流。相比线程池,信号量不需要线程切换,因此避免了不必要的开销。但是信号量不支持异步,也不支持超时,也就是说当所请求的服务不可用时,信号量会控制超过限制的请求立即返回,但是已经持有信号量的线程只能等待服务响应或从超时中返回,即可能出现长时间等待。线程池模式下,当超过指定时间未响应的服务, Hystrix会通过响应中断的方式通知线程立即结束并返回。

熔断器

现实生活中,可能大家都有注意到家庭电路中通常会安装一个保险盒,当负载过载时,保险盒中的保险丝会自动熔断,以保护电路及家里的各种电器,这就是熔断器的一个常见例子。Hystrix中的熔断器(Circuit Breaker)也是起类似作用,Hystrix在运行过程中会向每个commandKey对应的熔断器报告成功、失败、超时和拒绝的状态,熔断器维护并统计这些数据,并根据这些统计信息来决策熔断开关是否打开。如果打开,熔断后续请求,快速返回。隔一段时间(默认是5s)之后熔断器尝试半开,放入一部分流量请求进来,相当于对依赖服务进行一次健康检查,如果请求成功,熔断器关闭。
熔断器配置,Circuit Breaker主要包括如下6个参数:

1、circuitBreaker.enabled

是否启用熔断器,默认是TRUE。

2 、circuitBreaker.forceOpen

熔断器强制打开,始终保持打开状态,不关注熔断开关的实际状态。默认值FLASE。

3、circuitBreaker.forceClosed

熔断器强制关闭,始终保持关闭状态,不关注熔断开关的实际状态。默认值FLASE。

4、circuitBreaker.errorThresholdPercentage

错误率,默认值50%,例如一段时间(10s)内有100个请求,其中有54个超时或者异常,那么这段时间内的错误率是54%,大于了默认值50%,这种情况下会触发熔断器打开。

5、circuitBreaker.requestVolumeThreshold

默认值20。含义是一段时间内至少有20个请求才进行errorThresholdPercentage计算。比如一段时间了有19个请求,且这些请求全部失败了,错误率是100%,但熔断器不会打开,总请求数不满足20。

6、circuitBreaker.sleepWindowInMilliseconds

半开状态试探睡眠时间,默认值5000ms。如:当熔断器开启5000ms之后,会尝试放过去一部分流量进行试探,确定依赖服务是否恢复。

熔断器工作原理

下图展示了HystrixCircuitBreaker的工作原理:
image.png
熔断器工作的详细过程如下:

第一步,调用 allowRequest() 判断是否允许将请求提交到线程池

  1. 允许熔断器强制打开, circuitBreaker.forceOpen为true,不允许放行,返回。
  2. 如果熔断器强制关闭, circuitBreaker.forceOpen为true,允许放行。 此外不必关注熔断器实际状态,也就是说熔断器仍然会维护统计数据和开关状态,只是不生效而已。

    第二步,调用isOpen()判断熔断器开关是否打开

  3. 如果熔断器开关打开,进入第三步,否则继续;

  4. 如果一个周期内总的请求数小于circuitBreaker.requestVolumeThreshold的值,允许请求放行,否则继续;
  5. 如果一个周期内错误率小于circuitBreaker.errorThresholdPercentage的值,允许请求放行。否则,打开熔断器开关,进入第三步。

    第三步, 调用allowSingleTest()判断是否允许单个请求通行,检查依赖服务是否恢复

    如果熔断器打开,且距离熔断器打开的时间或上一次试探请求放行的时间超过
    circuitBreaker.sleepWindowInMilliseconds的值时,熔断器器进入半开状态,允许放行一个试探请求;否则,不允许放行。
    此外,为了提供决策依据,每个熔断默认维护了10个bucket,每秒一个bucket,当心的bucket被创建时,最旧的bucket会被抛弃。其中每个bucket维护了请求、失败、超时、拒绝的计数器,Hystrix负责收集并统计这些计数器。

image.png

第四步,回退降级

降级,通常指事务高峰期,为了保证核心服务正常运行,需要停掉一些不太重要的业务,或者某些服务不可用时,执行备用逻辑从故障服务中快速失败或快速返回,以保障主体业务不受影响。 Hystrix提供的降级主要是为了容错,保证当前服务不受依赖服务故障的影响,从而提高服务的健壮性。要支持回退或降级处理,可以重写 HystrixCommand的getFallBack方法或HystrixObservableCommand的resumeWithFallback方法。

1、Hystrix在以下几种情况下会走降级逻辑:

  • 执行construct()或run()抛出异常
  • 熔断器打开导致命令短路
  • 命令的线程池和队列或信号量的容量超额,命令被拒绝
  • 命令执行超时

2、降级回退方式
(1)Fail Fast快速失败
快速失败是最普通的命令执行方法,命令没有重写降级逻辑。 如果命令执行发生任何类型的故障,它将直接抛出异常。
(2)Fail Fast无声失败
指在降级方法中通过返回null,空Map,空List或其他类似的响应来完成。
(3)FallBack:Static
指在降级方法中返回静态默认值。 这不会导致服务以“无声失败”的方式被删除,而是导致默认行为发生。如:应用根据命令执行返回true / false执行相应逻辑,但命令执行失败,则默认为true。
(4)FallBack:Stubbed
当命令返回一个包含多个字段的复合对象时,适合以Stubbed 的方式回退。
(5)FallBack:Cache via Network
有时,如果调用依赖服务失败,可以从缓存服务(如redis)中查询旧数据版本。由于又会发起远程调用,所以建议重新封装一个Command,使用不同的ThreadPoolKey,与主线程池进行隔离。
(6)Primary+Secondary with FallBack
有时系统具有两种行为- 主要和次要,或主要和故障转移。主要和次要逻辑涉及到不同的网络调用和业务逻辑,所以需要将主次逻辑封装在不同的Command中,使用线程池进行隔离。为了实现主从逻辑切换,可以将主次command封装在外观HystrixCommand的run方法中,并结合配置中心设置的开关切换主从逻辑。由于主次逻辑都是经过线程池隔离的HystrixCommand,因此外观HystrixCommand可以使用信号量隔离,而没有必要使用线程池隔离引入不必要的开销。原理图如下:
image.png
主次模型的使用场景还是很多的。如当系统升级新功能时,如果新版本的功能出现问题,通过开关控制降级调用旧版本的功能。
通常情况下,建议重写getFallBack或resumeWithFallback提供自己的备用逻辑,但不建议在回退逻辑中执行任何可能失败的操作。

六、总结

介绍了Hystrix及其工作原理,还介绍了Hystrix线程池隔离、信号量隔离和熔断器的工作原理,以及如何使用Hystrix的资源隔离,熔断和降级等技术实现服务容错,从而提高系统的整体健壮性。
虽然Hystrix已经停更很久了,Spring Cloud体系的使用者和拥护者一片哀嚎,实际上,spring作为java最大的家族,根本不需要担心其中一两个组件的废弃, Hystrix的停更,只会催生更多更好的组件替代它,但是 Hystrix既然存在过,就一定就它存在的价值,既然存在,我就必须搞懂它。