4.5 降级回退方式
降级的常用处理方式,返回默认值,返回缓存里的值(包括本地缓存,远程redis缓存),但是回退的处理方式有不适合的场景。如写操作、批处理、计算等等。以上几种情况如果失败,则程序就要将错误返回给调用者。
Fail Fast快速失败
如果我们实现的是HystrixObservableCommand.java则 重写 resumeWithFallback方法。
Fail Silent 无声失败
返回null,空Map,空List。如图。重写getFallback()方法。
Fallback: Static 返回默认值
回退的时候返回静态嵌入代码中的默认值,这样就不会导致功能以Fail Silent的方式被清楚,也就是用户看不到任何功能了。而是按照一个默认的方式显示。
Fallback: Stubbed 自己组装一个值返回
在Fallback方法中组装初始化好的值。
Fallback: Cache via Network 利用远程缓存
通过远程缓存的方式,在失败的情况下再次发起一次remote请求缓存数据。由于是又发起一起远程调用,所以会重新封装一次Command,这个时候要注意,执行fallback的线程一定要跟主线程区分开,也就是重新命名一个ThreadPoolKey。
Primary + Secondary with Fallback 主次方式回退(主要和次要)
这种方式类似于我们上线一个新的功能,但为了防止新功能上线失败可以回退到老的代码,我们会做一个开关比如使用zookeeper做一个配置开关,可以动态切换到老代码功能。Hystrix使用通过一个配置来在两个command中进行切换。
代码如下:usePrimary可以通过ucc来配置。
4.6 隔离策略
执行依赖代码的线程与请求线程(比如Tomcat线程)分离,请求线程可以自由控制离开的时间,这也是我们通常说的异步编程,Hystrix是结合RxJava来实现的异步编程。通过设置线程池大小来控制并发访问量,当线程饱和的时候可以拒绝服务,防止依赖问题扩散。
4.6.1 线程隔离
优缺点
- 应用程序会被完全保护起来,即时依赖的一个服务线程池满了,也不会影响到应用程序的其他部分。
- 当依赖的服务恢复时,应用程序能恢复到正常的性能。
- 当参数配置错误时,线程池的状态会很快显示出来,比如延迟、超时、拒绝等。同时可以通过动态属性实时执行来处理纠正错误的参数配置。
- 如果服务的性能有变化,从而需要调整,比如增加或者减少超时时间,更改重试次数,就可以通过线程池指标动态属性修改,并不会影响到其他调用请求。注意:尽管线程池提供了隔离,但是我们的客户端底层代码也必须得有超时设置,不能无限制的阻塞以致线程池一直饱和。
- 线程池的主要缺点就是它增加了计算的开销,每个业务请求(被包装成命令)在执行的时候,会涉及到请求排队,调度和上下文切换。不过Netflix公司内部认为线程隔离开销足够小,不会产生重大的成本或性能的影响。
性能花费
Netflix API每天使用线程隔离的方式处理10亿多的Hystrix Command任务,每个API实例都有40多个线程池,每个线程池都有5-20个线程(大多数设置为10)
下图显示了一个HystrixCommand在单个API实例上每秒执行60个请求(每个服务器每秒执行大约350个线程执行总数)。从图上可知:
在中间偏下位置,用单一线程是没有性能消耗的。
TP90的消耗大概是单一线程为3ms。
单一线程TP99大概是有9ms的消耗。但是增长的性能花费远小于单一线程增长的执行时间(网络请求),线程执行时间从2-28ms然而花费从0-9ms。
对大多数Netflix使用的案例,这样TP90或者更高的电路响应时间(花销)是可以接受的,这样换取了系统的韧性。
4.6.2 信号量隔离
对于不依赖网络访问的服务,比如只依赖内存缓存这种情况下,就不适合用线程池隔离技术,而是采用信号量隔离。
信号量隔离只是限制了总的并发数,服务使用主线程进行同步调用,即没有线程池。因此,某个服务的如果只是想限制总并发调用量或者调用的服务不涉及远程调用的话,可以使用轻量级的信号量来实现。
4.6.3 隔离策略对比
这张图说明了线程池隔离和信号量隔离的主要区别:线程池方式下业务请求线程和执行依赖的服务的线程不是同一个线程;信号量方式下业务请求线程和执行依赖服务的线程是同一个线程。
下表对比了线程池和信号量主要的特点异同。信号量和线程池隔离方式都支持熔断和限流。
信号量隔离图解。
线程池隔离图解。
4.7 Collapsing
使用场景:HystrixCollapser用于对多个相同业务的请求合并到一个线程甚至可以合并到一个连接中执行,降低线程交互次和IO数,但必须保证他们属于同一依赖。
- 产生原因?无论是SOA架构还是微服务架构的系统,往往会通过RPC方式或者HTTP请求方式依赖外部的接口。而远程调用过程中最常见的问题就是通信消耗与连接数占用。在高并发情况下,因通信次数的增加,调用方在本地线程池缓存的请求数、被调用方的性能消耗和网络通信次数都会导致总的通信时间变得不那么理想。为了优化这些问题,Hystrix提供了HystrixCollapser来实现请求的合并,以减少网络通信消耗和本地线程的占用。
- HystrixCollapser实现了在HystrixCommand之前放置一个合并处理器,它会在一个很短的时间内(通过timerDelayInMilliseconds参数设置,默认是10毫秒)内对同一依赖服务的多个请求进行整理合并以批量方式发起请求(服务端需提供批量的接口)。通过HystrixCollaper的封装,开发者不需要去关注线程合并和请求结果分发的细节,只需关注批量化服务。如下图,没有Collapsing时,请求数=线程数=网络连接数。当使用Collapsing,将每个提交的请求合并到Collapser,通过1个线程完成数据的获取,所以,窗口中的请求数=1个线程=1个网络连接。
- 请求合并的使用场景
在选择是否使用Collapers时,主要考虑下面两个方面。
(1)请求命令本身的延迟。如果依赖服务的请求命令本身是一个高延迟的命令,则可以使用请求合并器,因为延迟时间窗的时间消耗就显得微不足道了。
(2)延迟时间窗内的并发量。如果时间窗内只有很小的并发,这样反而会导致系统瓶颈,因为每个请求需要多消耗一个时间窗才响应。如果一个时间窗内有很高的并发,并且服务方也实现了批量处理接口,那么Collapser可以有效减小网络连接数和提升系统吞吐量。此时延迟时间窗所增加的消耗就忽略不计了。
对于Collapser,个人建议慎用。除非你能准确评估两者的利弊。
5. 实例
5.1 Hello World
5.2 SpringMVC-注解方式
步骤1:获取切入点方法;
步骤2:根据方法的注解HystrixCommand或者HystrixCollapser生成相应的CommandMetaHolderFactory或者CollapserMetaHolderFactory类。
步骤3:将原方法的属性set进metaHolder中;
步骤4:根据metaHolder生成相应的HystrixCommand,包含加载hystrix配置信息。commandProperties加载的优先级为前缀hystrix.command.commandKey > hystrix.command.default > defaultValue(原代码默认);threadPool配置加载的优先级为 前缀hystrix.threadpool.groupKey.> hystrix.threadpool.default.> defaultValue(原代码默认)。
步骤5:执行命令。
倘若需要给该方法指定groupKey和commandKey定义其fallback方法,则可通过添加注解属性来实现。
5.2.1 Command Properties
Execution
包括
execution.isolation.strategy、
execution.isolation.thread.timeoutInMilliseconds、
execution.timeout.enabled、
execution.isolation.thread.interruptOnTimeout、
execution.isolation.thread.interruptOnCancel、
execution.isolation.semaphore.maxConcurrentRequests。
Fallback
包括
fallback.isolation.semaphore.maxConcurrentRequests、
fallback.enabled。
Circuit Breaker
包括
circuitBreaker.enabled、
circuitBreaker.requestVolumeThreshold、
circuitBreaker.sleepWindowInMilliseconds、
circuitBreaker.errorThresholdPercentage、
circuitBreaker.forceOpen、
circuitBreaker.forceClosed。
Metrics
包括
metrics.rollingStats.timeInMilliseconds、
metrics.rollingStats.numBuckets、
metrics.rollingPercentile.enabled、
metrics.rollingPercentile.timeInMilliseconds、
metrics.rollingPercentile.numBuckets、
metrics.rollingPercentile.bucketSize、
metrics.healthSnapshot.intervalInMilliseconds。
Request Context
包括
requestCache.enabled、
requestLog.enabled。
5.2.2 Collapser Properties
包括
maxRequestsInBatch、
timerDelayInMilliseconds、
requestCache.enabled。
5.2.3 Thread Pool Properties
包括coreSize、maximumSize、maxQueueSize、queueSizeRejectionThreshold、keepAliveTimeMinutes、allowMaximumSizeToDivergeFromCoreSize、metrics.rollingStats.timeInMilliseconds、metrics.rollingStats.numBuckets。
5.3 功能总结
5.3.1 Core function
- Isolate
Maintain a small thread pool for each dependency.
-- avoid cascading failures into whole system.
-- rapidly recover
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool"))
- Latent control
NOT available when choose SEMAPHORE isolation
.withExecutionTimeoutInMilliseconds(3000)))
- Fail fast
a. If pool is full, be immediately rejected instead of queued up;
b. Circuit breaker (https://github.com/Netflix/Hystrix/wiki/How-it-Works#circuit-breaker)
Fallback and degrade gracefully implements getFallback() method
5.3.2 Extension function
- Request Collapsing
- Request Caching
- Near real-time monitoring, alerting, and operational control
6. 网关引入和实现思路
6.1 接入姿势
姿势很重要!从Controller引入还是从RPC层引入?如果从Controller引入,Controller对应的方法由一个线程去通过RPC方式获取所有的资源。如果是从RPC层引入,则每个RPC方法对应一个线程池,这样可以灵活控制每个RPC接口的访问情况。网关接口使用这种方式引入。
6.2 实现思路
参数设置依据
Thread Size = peak healthy × 99th percentile latency in seconds + some breathing room(线程池大小 = 峰值QPS * 99耗时 + 预留空间 )
超时设定标准
With retry,Time = 99th mean-time + 50th mean-time
Without Retry,Time = 99.5meantime
7. 总结
本文主要从hystrix原理和实现两个方面对hystrix进行讲解。其中对原理的实现上可能会有没有考虑到的问题,因公司内部已有监控的服务,对hystrix监控没有进行讲解,其他有疑问之处,欢迎拍砖。
8. 参考
降级回退方式
各种注解属性http://zyouwei.com/%E6%8A%80%E6%9C%AF%E7%AC%94%E8%AE%B0/Java/Hystrix-configuration.html
请求合并
https://www.jianshu.com/p/ddaa71462b26
hystrix-翻译比较好的文章
http://youdang.github.io/2016/02/05/translate-hystrix-wiki-how-it-works/
http://www.cnblogs.com/java-synchronized/p/7927726.html
https://www.jianshu.com/p/73a07e06a9d5?from=timeline
http://blog.csdn.net/qq_17751605/article/details/51225976
http://blog.csdn.net/xiaojia1100/article/details/65631778