微服务中Hystrix的作用详解
前言
本文在书写过程中,参考了大量文档,如《Spring Cloud与Docker微服务架构实战》周立著、红帽Openshift官方技术文档、Openshift社区相关文档。本文在书写过程中,也引用了互联网的一些概念描述,文章最后会列出参考文献链接。
什么是Hystrix
笔者在之前文章《从一个实验看微服务架构---不谈理念讲干货》中,简单介绍了基于Openshift实现微服务的方法。在实验中,所有微服务都通过容器来实现:
在《从一个实验看微服务架构---不谈理念讲干货》文章中,笔者提到了Hystrix作为熔断器的存在,但介绍不是很深,本次我们详细看一下。
首先,Hystrix是Netflix公司开源的一个项目。那么Netflix公司是做什么的呢?这是一个有意思的话题。Netflix(Nasdaq NFLX) 成立于1997年,是一家在线影片租赁提供商,主要提供Netflix超大数量的DVD并免费递送,总部位于美国加利福尼亚州洛斯盖图。可能很多人不知道Netflix,但有个很有名的美剧-纸牌屋,其每集片头都会显示Netflix:
所以说,开源社区需要全社会的参与。
实际上,netflix和K8S有个集成的项目,叫Kubeflix。也就是说netflix把它的一些开源方案直接与K8S在社区里集成。Kubeflix主要有四个方案:Hystrix、Turbine、Ribbon、API网关。
Hystrix默认只能显示一个服务的治理信息,turbine是可以帮助把很多个服务和服务实例的信息进行聚合,hystrix dashboard里面的信息才是整体的。如下图显示,hystrix dashboard会读取turbine收集的数据:
Ribbon 是 Netflix 发布的云中间层服务开源项目,其主要功能是提供客户侧软件负载均衡算法,将 Netflix 的中间层服务连接在一起。
Hystrix详解
有个词,叫“雪崩效应”,相信很多人都听过。它其实是从“雪球越滚越大”的现象抽象出来的。在单体应用中,多个业务的功能模块放在一个应用中(如三层架构的网银),功能模块之前是紧耦合,单体应用要么整体稳定运行,要么整体出现问题,整体不可用。
按照上图,Ola是Hola的基础服务、Hola是Aloha的基础服务、Aloha是Bonjpur的基础服务。那么,如果Ola微服务出现问题,不可调用,那显然会影响到Hola的调用、Aloha调用、Bonjpur的调用。这就像雪球一样,越滚越大,越到后面,影响越严重。
要想避免雪崩现象,就需要有容器机制,采用断路模式。为每个微服务前面加一个“保险丝”。当电流过大的时候(如服务访问超时,并且超过设定的重试次数),保险丝烧断,中断客户端对该应用的访问,而访问其他好的应用。
微服务常见实现容错的工具是Hystrix。Hystrix实现容错主要有以下两点:
1. 设置网络超时
网络超时指的是,当对一个微服务的远程调用,如果响应太慢,那远程调用对应的这个线程/进程就得不到释放,如果数量比较多,最终大量消耗系统资源。因此就需要为每个网络请求设置超时时间。
2.使用断路器
断路器指的是,当对摸一个微服务的请求有大量超时的时候,以让这个微服务对外通讯中断,实现快速失败。这就像家里的保险丝一样。
同时,断路器可以对已经被断路的微服务进行检测,查看微服务是否已经恢复正常,是的话,就恢复该应用对外提供服务。就像下面这样(示意图)
正常情况下,A、B、C三个微服务的断路器都是关闭的。
1.如果一段时间内,对A微服务的访问失败率或错误率达到一定阈值;断路器打开,对A微服务的请求全部被中断。
2.断路器打开一段时间后,断路器允许一个请求访问微服务A,检测是否调用成功,如果成功,则关闭断路器,失败,则断路器保持打开的状态。
Hytrix参数设置(引用http://blog.csdn.net/caomiao2006/article/details/50000511):
1):Command 配置
Command配置源码在HystrixCommandProperties,构造Command时通过Setter进行配置
具体配置解释和默认值如下
//使用命令调用隔离方式,默认:采用线程隔离,ExecutionIsolationStrategy.THREAD
private final HystrixProperty<ExecutionIsolationStrategy> executionIsolationStrategy;
//使用线程隔离时,调用超时时间,默认:1秒
private final HystrixProperty<Integer> executionIsolationThreadTimeoutInMilliseconds;
//线程池的key,用于决定命令在哪个线程池执行
private final HystrixProperty<String> executionIsolationThreadPoolKeyOverride;
//使用信号量隔离时,命令调用最大的并发数,默认:10
private final HystrixProperty<Integer> executionIsolationSemaphoreMaxConcurrentRequests;
//使用信号量隔离时,命令fallback(降级)调用最大的并发数,默认:10
private final HystrixProperty<Integer> fallbackIsolationSemaphoreMaxConcurrentRequests;
//是否开启fallback降级策略 默认:true
private final HystrixProperty<Boolean> fallbackEnabled;
// 使用线程隔离时,是否对命令执行超时的线程调用中断(Thread.interrupt())操作.默认:true
private final HystrixProperty<Boolean> executionIsolationThreadInterruptOnTimeout;
// 统计滚动的时间窗口,默认:5000毫秒circuitBreakerSleepWindowInMilliseconds
private final HystrixProperty<Integer> metricsRollingStatisticalWindowInMilliseconds;
// 统计窗口的Buckets的数量,默认:10个,每秒一个Buckets统计
private final HystrixProperty<Integer> metricsRollingStatisticalWindowBuckets; // number of buckets in the statisticalWindow
//是否开启监控统计功能,默认:true
private final HystrixProperty<Boolean> metricsRollingPercentileEnabled;
// 是否开启请求日志,默认:true
private final HystrixProperty<Boolean> requestLogEnabled;
//是否开启请求缓存,默认:true
private final HystrixProperty<Boolean> requestCacheEnabled; // Whether request caching is enabled.
2)熔断器(Circuit Breaker)配置
Circuit Breaker配置源码在HystrixCommandProperties,构造Command时通过Setter进行配置,每种依赖使用一个Circuit Breaker
// 熔断器在整个统计时间内是否开启的阀值,默认20秒。也就是10秒钟内至少请求20次,熔断器才发挥起作用
private final HystrixProperty<Integer> circuitBreakerRequestVolumeThreshold;
//熔断器默认工作时间,默认:5秒.熔断器中断请求5秒后会进入半打开状态,放部分流量过去重试
private final HystrixProperty<Integer> circuitBreakerSleepWindowInMilliseconds;
//是否启用熔断器,默认true. 启动
private final HystrixProperty<Boolean> circuitBreakerEnabled;
//默认:50%。当出错率超过50%后熔断器启动.
private final HystrixProperty<Integer> circuitBreakerErrorThresholdPercentage;
//是否强制开启熔断器阻断所有请求,默认:false,不开启
private final HystrixProperty<Boolean> circuitBreakerForceOpen;
//是否允许熔断器忽略错误,默认false, 不开启
private final HystrixProperty<Boolean> circuitBreakerForceClosed;
3):命令合并(Collapser)配置
Command配置源码在HystrixCollapserProperties,构造Collapser时通过Setter进行配置
//请求合并是允许的最大请求数,默认: Integer.MAX_VALUE
private final HystrixProperty<Integer> maxRequestsInBatch;
//批处理过程中每个命令延迟的时间,默认:10毫秒
private final HystrixProperty<Integer> timerDelayInMilliseconds;
//批处理过程中是否开启请求缓存,默认:开启
private final HystrixProperty<Boolean> requestCacheEnabled;
4):线程池(ThreadPool)配置
/**
配置线程池大小,默认值10个.
建议值:请求高峰时99.5%的平均响应时间 + 向上预留一些即可
*/
HystrixThreadPoolProperties.Setter().withCoreSize(int value)
/**
配置线程值等待队列长度,默认值:-1
建议值:-1表示不等待直接拒绝,测试表明线程池使用直接决绝策略+ 合适大小的非回缩线程池效率最高.所以不建议修改此值。
当使用非回缩线程池时,queueSizeRejectionThreshold,keepAliveTimeMinutes 参数无效
*/
HystrixThreadPoolProperties.Setter().withMaxQueueSize(int value)
Hytrix界面展示
在笔者是实验环境中,Hystrix-dashboard是一个容器, turbine也是个容器:
点击Monitor Stream,进入主界面:
在监控界面中,具体的指标描述,参照下图,其中Circut代表断路器的状态,下图是关闭的状态:
我们查看实验环境中,一个微服务的状态.hola service:
将这个微服务对应的容器和rc删掉,先进行查看:
删除rc,dc和pod
查看Hytrix,近10s的访问失败率是100%,此时熔断器还是关闭状态:
在过一小会(1分钟左右),熔断器打开,处于open状态:
重建dc后,pod和service重建后,过一会holo的状态恢复正常,断路器关闭:
参考文献:
http://blog.csdn.net/caomiao2006/article/details/50000511
https://github.com/Netflix/Hystrix