Java虚拟机:SpringCloud的限流、降级和熔断——Hystrix( 三 )


(三)几种方法的关系
Java虚拟机:SpringCloud的限流、降级和熔断——Hystrix
本文插图

  • execute()实际是调用了queue().get()
  • queue()实际调用了toObservable().toBlocking().toFuture()
  • observe()实际调用toObservable()获得一个cold Observable , 再创建一个ReplaySubject对象订阅Observable , 将源Observable转化为hot Observable 。 因此调用observe()会自动触发执行run()/construct() 。
Hystrix 总是以Observable的形式作为相应返回 , 不同执行命令的方法只是进行了相应的转换 。
Java虚拟机:SpringCloud的限流、降级和熔断——Hystrix
本文插图

五、 Hystrix 容错 Hystrix 的容错主要是通过添加容许延迟和容错方法 , 帮助控制这些分布式服务之间的交互 。 还通过隔离服务之间的访问点 , 阻止它们之间的级联故障以及提供退回选项来实现这一点 , 从而提高系统的整体弹性 。Hystrix主要提供了一下几种容错方法:
  • 资源隔离
  • 熔断
  • 降级
(一)资源熔断
资源隔离主要指对线程的隔离 。Hystrix提供了两种线程隔离的方式:线程池和信号量 。
1、线程隔离-线程池
Hystrix还通过命令模式对发送请求的对象和执行请求的对象进行解耦 , 将不同类型的业务请求封装为对应的命令请求 。 如订单服务查询商品 , 查询商品请求->商品command;商品服务查询库存 , 查询库存请求->库存command 。 并且为每个类型的command配置一个线程池 , 当第一次创建command时 , 根据配置创建一个线程池 , 并放入ConcurrentHashMap , 如商品command:

Java虚拟机:SpringCloud的限流、降级和熔断——Hystrix
本文插图

后续查询商品的请求创建command时 , 将会重用已创建的线程池 。 线程池隔离之后的服务依赖关系:
Java虚拟机:SpringCloud的限流、降级和熔断——Hystrix
本文插图

通过发送请求线程与执行请求的线程分离 , 可有效防止发生级联故障 。 当线程池或请求队列饱和时 , Hystrix将拒绝服务 , 使得请求线程可以快速失败 , 从而避免依赖问题扩散 。
线程池隔离优点:
  • 保护应用程序以免受来自依赖故障的影响 , 指定依赖线程池饱和不会影响应用程序的其余部分 。
  • 当引入新客户端lib时 , 即使发生问题 , 也是在lib中 , 并不会影响其他内容 。
  • 当依赖从故障恢复正常时 , 应用程序会立即恢复正常的性能 。
  • 当应用程序一些配置参数错误时 , 线程池的运行状况会很快检测到这一点(通过增加错误、延迟、超时、拒绝等) , 同时可以通过动态属性进行实时纠正错误的参数配置 。
  • 如果服务的性能有变化 , 需要实时调整 , 比如增加或减少超时时间 , 更改重试次数 , 可以通过线程池指标状态属性修改 , 而且不会影响到其它调用请求 。
  • 除了隔离优势外 ,Hystrix 拥有专门的线程可提供内置的并发功能 , 使得可以在同步调用之上构建异步门面(外观模式) , 为异步编程提供了支持( Hystrix 引入了R小Java异步框架) 。
注意:尽管线程池提供了线程隔离 , 我们的客户端底层代码也必须要有超时设置或响应线程中断 , 不能无限制的阻塞以致线程池一直饱和 。
缺点:
线程池的主要缺点是增加了计算开销 。 每个命令的执行都在单独的线程完成 , 增加了排队、调度和上下文切换的开销 。 因此 , 要使用 Hystrix, 就必须接受它带来的开销 , 以换取它所提供的的好处 。
通常情况下 , 线程池引入的开销足够小 , 不会有重大的成本和性能影响 。 但对于一些访问延迟极低的服务 , 如只依赖内存缓存 , 线程池引入的开销就比较明显了 , 这时候使用线程池隔离技术就不合适了 , 我们需要考虑更轻量级的方式 , 如信号量隔离 。


推荐阅读