Hystrix是什么?
在分布式环境下,系统不可避免地会遇到依赖服务失效的问题,这些问题可能是依赖服务的高延迟,或者依赖服务抛出异常。使用 Hystrix 增加延迟/失败容忍逻辑,能帮助你解决这些服务之间交互的问题。Hystrix 能使你的系统在出现依赖服务失效的时候,通过隔离系统所依赖的服务,防止服务级联失败,同时提供失败回退机制,更优雅地应对失效,并使你的系统能更快地从异常中恢复。
Hystrix 的历史
Hystrix 项目由 Netflix API 组于 2011 年创立,创立之初主要用于应对系统快速恢复的需求。到了 2012 年,Hystrix 项目日益完善和成熟,Netflix 公司内部越来越多的组开始使用它。现在,数以百亿计的通过线程进行依赖隔离和数以千亿计的通过信号量进行依赖隔离的跨系统请求通过 Hystrix 发出,也正因为此,Netflix 的服务在系统可用性和快速恢复能力方面有了长足的长进。
下面这些链接详细介绍了 Hystrix,以及它所面临的挑战:
- Making Netflix API More Resilient
- Fault Tolerance in a High Volume, Distributed System
- Performance and Fault Tolerance for the Netflix API
- Application Resilience in a Service-oriented Architecture
- Application Resilience Engineering & Operations at Netflix
Hystrix 能做什么?
Hystrix 被设计用来:
- 在通过第三方客户端访问(通常是通过网络)依赖服务出现高延迟或者失败时,为系统提供保护和控制
- 在分布式系统中防止级联失败
- 快速失败(Fail fast)同时能快速恢复
- 提供失败回退(Fallback)和优雅的服务降级机制
- 提供近实时的监控、报警和运维控制手段
Hystrix 能解决什么问题?
应用在复杂的分布式结构中,可能会依赖许多其他的服务,并且这些服务都不可避免地有失效的可能。如果一个应用没有与依赖服务的失效隔离开来,那么它将有可能因为依赖服务的失效而失效。
例如,一个应用依赖了 30 个服务,并且每个服务能保证 99.99% 的可用率,下面是一些计算结果:
99.9930 = 99.7% 可用率
10亿次请求×0.3% = 3,000,000次失效
即使所有依赖的服务都能达到 99.99% 的可用率,这个系统每个月还是会有大于两小时的不可用时间
而现实更加残酷,如果你没有针对整个系统做快速恢复,即使所有依赖只有 0.01% 的不可用率,累积起来每个月给系统带来的不可用时间也有数小时之多。
当所有依赖都正常,一个请求的拓扑结构如下所示:
当一个后端依赖服务有延迟,它会阻塞整个用户请求:
在高QPS环境下,一个后端依赖服务的延迟,会导致服务器上的资源都被阻塞。
应用中每一个网络请求或者间接通过客户端库发出的网络请求都是潜在的导致应用失效的原因。更严重的是,这些应用可能被其他服务依赖,由于每个服务都有诸如请求队列,线程池,或者其他系统资源等,一旦某个服务失效或者延迟增高,会导致更严重的级联失效。
如果这些网络请求通过第三方客户端发出,问题会变得更加严重,因为这些第三方客户端对于应用来说相当于『黑盒』——无法了解其实现细节,随时可能发生变更,网络/资源配置随客户端的不同而不同,同时又难以监控和修改。同时,应用依赖链中的服务可能非常耗时,或者这些可能导致问题的网络请求根本没有被我们的应用显式地调用!
网络连接可能失败或者降级、服务或者服务器可能失效或者变慢、依赖的库或者部署的服务可能发生行为变更或性能变更,亦或是依赖的服务本身有 bug。
以上种种,都会导致失效或高延迟,为了使我们的系统更加鲁棒,不至于因为单个服务出现上述问题而失效,我们需要将这些问题进行隔离。
Hystrix 的设计原则
- 防止单个依赖耗尽容器(例如 Tomcat)内所有用户线程
- 降低系统负载,对无法及时处理的请求快速失败(fail fast)而不是排队
- 提供失败回退,以在必要时让失效对用户透明化
- 使用隔离机制(例如『舱壁』/『泳道』模式,熔断器模式等)降低依赖服务对整个系统的影响
- 针对系统服务的度量、监控和报警,提供优化以满足近实时性的要求
- 在 Hystrix 绝大部分需要动态调整配置并快速部署到所有应用方面,提供优化以满足快速恢复的要求
- 能保护应用不受依赖服务的整个执行过程中失败的影响,而不仅仅是网络请求
Hystrix 如何实现上述功能?
- 将所有请求外部系统(或者叫依赖服务)的逻辑封装到
HystrixCommand
或者HystrixObservableCommand
对象中,这些逻辑将会在独立的线程中被执行(利用了设计模式中的 Command模式) - 对那些耗时超过设置的阈值的请求,Hystrix 采取自动超时的策略。该策略默认对所有
Command
都有效,当然,你也可以通过设置Command
的配置以自定义超时时间,以使你的依赖服务在引入 Hystrix 之后能达到 99.5% 的性能 - 为每一个依赖服务维护一个线程池(或者信号量),当线程池占满,该依赖服务将会立即拒绝服务而不是排队等待
- 划分出成功、失败(抛出异常)、超时或者线程池占满四种请求依赖服务时可能出现的状态
- 引入『熔断器』机制,在依赖服务失效比例超过阈值时,手动或者自动地切断服务一段时间
- 当请求依赖服务时出现拒绝服务、超时或者短路(多个依赖服务顺序请求,前面的依赖服务请求失败,则后面的请求不会发出)时,执行该依赖服务的失败回退逻辑
- 近实时地提供监控和配置变更
当使用 Hystrix 包装了你的所有依赖服务的请求后,上面图中所示的系统拓扑将会变成如下形式:
每个依赖服务都被隔离开来,Hystrix 会严格控制其在延迟发生时对资源的占用,并在任何失效发生时,执行失败回退逻辑。