1.Hystrix特性
- 在访问(通常是通过网络)第三方依赖库时,提供保护和控制latency和failure
- 在复杂的分布式系统中停止cascading failure
- 快速失败和快速恢复
- Fallback和优雅降级
- 提供接近实时的监控、警告和操作控制
2.Hystrix解决的问题
在复杂庞大的分布式系统中,服务不可避免的会出现问题,即使服务只有一段很小的时间不可用,但是在成千上万的访问量下,很快会导致整个应用的线程耗尽进而导致应用崩溃,所以对于服务调用失败或超时这种情况,我们需要有一种隔离机制,来防止部分应用的不可用对整个应用的影响。
3.Hystrix如何实现这个目标
- 把所有对外部系统的调用全部用
HystrixCommand
或HystrixObservableCommand
包装,它们实际上是在一个隔离的线程中执行的 - 如果调用时间超过你定义的时间,那么调用被作为超时处理
- 为每一个依赖维护一个小的线程池(或semaphore),如果线程池(或semaphore)满了,对于这个依赖的请求会被立即拒绝而不是放在队列里等待处理
- 度量成功、失败(客户端抛出的异常)、超时和线程拒绝信息
- 如果调用服务的错误率达到阈值,则在一段时间内断开断路器来停止对特定服务的请求
- 近于实时的监控度量信息和配置的变更
4.Hystrix如何工作
4.1调用服务流程图
Hystrix调用服务流程图4.2流程解释
- 构造一个
HystrixCommand
或HystrixObservableCommand
- 这个对象代表对依赖服务的调用请求
-
HystrixCommand
对象执行后会直接返回一个响应 -
HystrixObservableCommand
对象执行后会返回一个Observable
- 执行Command
- 有4中方法可以执行command(前两个只能用于
HystrixCommand
) -
execute()
——阻塞调用,直到返回响应(或抛出异常) -
queue()
——返回一个Future
来获取响应 -
observe()
——订阅代表响应的Observable
并且返回一个Observable
-
toObservable()
——返回一个Observable
,当你订阅它的时候,Hystix command会执行并且emit它的响应 -
execute()
实际上是执行了queue().get()
;queue()
实际上是执行了toObservable().toBlocking().toFuture()
。所以每一个HystrixCommand
最终都是由Observable
实现支持的
- 有4中方法可以执行command(前两个只能用于
- 检查响应是否被缓存。如果这个command开启了缓存,并且这个请求的响应已被缓存,则直接返回缓存
- 检查断路器是否打开。如果打开,Hystrix会直接执行Fallback逻辑
- 检查Thread Pool/Queue/Semaphore是否已经满了。如果这个command关联的Thread Pool/Queue/Semaphore已经满了,Hystrix会直接执行Fallback逻辑
-
HystrixObservableCommand.construct()
或HystrixCommand.run()
,也就是执行对依赖服务的请求-
HystrixCommand.run()
——返回响应数据或抛出一个异常 -
HystrixObservableCommand.construct()
——返回一个Observable
,它会emits响应数据或发送一个onError
通知 - 如果
run()
或construct()
执行超时了,线程会抛出一个TimeoutException
,Hystrix会直接执行Fallback逻辑,但是依赖服务可能会继续执行,即使返回了结果,Hystrix也会丢弃
-
- 计算断路器健康状态。Hystrix会像断路器报告成功、失败、拒绝和超时,断路器会利用这些数据计算健康状态,决定是否应该断开。
- 执行Fallback逻辑。如果
construct()
或run()
执行失败或超时,则会执行Fallback逻辑。如果没有实现Fallback逻辑或执行Fallback出错,-
execute()
——抛出一个异常 -
queue()
——成功返回Future
,但是调用get()
会抛出异常 -
observe()
——返回Observable
,但是当你订阅它时,会直接终止并调用onError
方法 -
toObservable()
——返回Observable
,但是当你订阅它时,会直接终止并调用onError
方法
-
- 返回成功响应
5.断路器
HystrixCommand与断路器交互图断路器开闭的过程如下:
- 假设经过断路器的请求数量符合阈值(
HystrixCommandProperties.circuitBreakerRequestVolumeThreshold()
) - 然后,假设错误率超过了错误率阈值(
HystrixCommandProperties.circuitBreakerErrorThresholdPercentage()
) - 然后,断路器会由
CLOSED
变为OPEN
- 当断路器打开,它会短路所有的请求
- 一段时间后(
HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds()
),下一个请求会允许通过(此时断路器处于HALF-OPEN
状态)。如果请求失败,断路器会返回到OPEN
状态,再经过一个休眠窗口期;如果请求成功,断路器会变为CLOSED
状态
6.隔离
Hystrix使用舱壁模式来隔离每一个依赖服务并限制对他们的并发访问。
6.1Threads & Thread Pools
-
Hystrix为每个依赖服务提供了单独的线程池,所以底层执行的延迟只会使对应服务的线程池饱和,而不会影响到其他服务
独立的线程池 - 注意:尽管我们由线程隔离的机制,但是底层代码应该对超时或线程中断请求进行处理,防止线程无限期的阻塞和线程池饱和
- 线程隔离的缺点:增加了计算开销
6.2Semaphores
你可以使用semaphores对依赖服务的并发调用数量。这允许Hystrix在不使用ThreadPool的情况下卸下负载,但这种方式不允许超时或退出。
-
HystrixCommand
和HystrixObservableCommand
在两个地方支持semaphores:- Fallback:当Hystrix使用Tomcat线程检索Fallbacks时
- Execution:如果设置
execution.isolation.strategy
为SEMAPHORE
,Hystrix会使用semaphores来限制执行command的线程数
- 注意:如果一个通过semaphore方式隔离的依赖服务出现延迟,父线程会一直保持阻塞知道底层网络调用超时
6.3请求折叠
请求折叠可以使多个请求被单个 HystrixCommand
实例批量的执行。请求折叠的好处是可以减少线程和网络连接的使用。不过需要注意的是,如果调用的方法处理时间比较长的话,则不适合请求折叠,因为这回增加请求超时的可能性,请求折叠适用于那些处理时间端的请求。
7.Hystrix使用
- 所有的异常都会被用于统计失败次数和触发
getFallback()
和circuit-breaker逻辑,除了HystrixBadRequestException
以外。如果想要抛出异常的话,可以把异常包装为HystrixBadRequestException
,然后通过getCause()
获取原来的异常。 -
HystrixCommandKey
用来代表HystrixCommand
的key,可以用于监控、断路器、指标发布、缓存等用途 -
Hystrix
使用HystrixCommandGroupKey
来把报告、报警、仪表盘或team/library所有权的命令组合在一起,默认情况下Hystrix
会使用它来定义command thread-pool -
HystrixThreadPoolKey
用来代表HystrixThreadPool
的key,可以用于监控、指标发布、缓存等用途 - 可以通过实现
HystrixCommand
或HystrixObservableCommand
对象的getCacheKey()
方法来启用Request Cache
网友评论