实战Hystrix-降级,超时
在整个SpringCloud构建微服务的体系中,有一个提供超时机制,限流,熔断,降级最全面
的实现:Hystrix(豪猪) 翻译过来表示:自身带刺,有自我保护的意思,外国人起名字还是
很有意思滴。当然Hystrix并不是Spring的,而是NetFlix公司开源的。那么Spring只是把它
拿过来,在他的基础上面做了一些封装,然后加入到了SpringCloud中,实现高可用的分布
式微服务架构
Hystrix博大精深,功能齐全
直接看代码示例:06-ms-consumer-order-ribbon-hystrix-customizing
1、引入Springcloud Hystrix依赖, 那么在哪里引入呢?
一定是在调用方来做降级,所以需要在消费者这边引入Hystrix,也就是我们的订单微服务
方
2、那么Hystrix是怎么做到降级的呢?
他通过一种叫做“命令模式”的方式,继承(HystrixCommand类)来包裹具体的服务调用
逻辑(run方法), 并在命令模式中添加了服务调用失败后的降级逻辑(getFallback),见
(OrderServiceCommand类)
3、用Hystrix的注解@HystrixCommand可以更简单的实现上面的降级逻辑
见代码示例:06-ms-consumer-order-ribbon-hystrix-fallback
直接在接口调用方的方法上增加注解@HystrixCommand(fallbackMethod =
“findByIdFallback”)
4、超时回退怎么实现?
在用户微服务工程(06-ms-provider-user)里将UserController的findById接口增加执行等
待时间,让该接口的执行时间变长,Hystrix调用接口默认两秒超时,超时后会自动执行降
级方法
实战Hystrix-熔断,限流
熔断怎么实现?见示例:06-ms-consumer-order-ribbon-hystrix-fusing
在用户微服务工程(06-ms-provider-user)里将UserController的findById接口增加模拟报
错代码
测试报错和正常的情况,我们可以看到当报错达到一定阈值时,会自动熔断,阈值可以配
置,如下:
# 一个rolling window内最小的请求数。如果设为20,那么当一个rolling window的时间内
(比如说1个rolling window是10秒)收到19个请求,即使19个请求都失败,也不会触发
circuit break。默认20
hystrix.command.default.circuitBreaker.requestVolumeThreshold
# 触发短路的时间值,当该值设为5000时,则当触发circuit break后的5000毫秒内都会拒
绝request,也就是5000毫秒后才会关闭circuit。默认5000
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds
熔断器原理
熔断器模式定义了熔断器开关相互转换的逻辑:
服务的健康状况 = 请求失败数 / 请求总数.
熔断器开关由关闭到打开的状态转换是通过当前服务健康状况和设定阈值比较决定的.
1、当熔断器开关关闭时, 请求被允许通过熔断器. 如果当前健康状况高于设定阈值, 开关
继续保持关闭. 如果当前健康状况低于设定阈值, 开关则切换为打开状态.
2、当熔断器开关打开时, 请求被禁止通过.
3、当熔断器开关处于打开状态, 经过一段时间后, 熔断器会自动进入半开状态, 这时熔断
器只允许一个请求通过. 当该请求调用成功时, 熔断器恢复到关闭状态. 若该请求失败, 熔
断器继续保持打开状态, 接下来的请求被禁止通过.
熔断器的开关能保证服务调用者在调用异常服务时, 快速返回结果, 避免大量的同步等待.
并且熔断器能在一段时间后继续侦测请求执行结果, 提供恢复服务调用的可能.
限流,线程资源隔离怎么实现?见示例:06-ms-consumer-order-ribbon-hystrix-thread-
isolation
在用户微服务工程(06-ms-provider-user)里将UserController的findById接口模拟执行等
待的代码
在订单微服务工程(06-ms-consumer-order-ribbon-hystrix-thread-isolation)中修改接口
超时配置为20秒:
然后用注解配置线程池大小:
部分注解意思如下:
CommandGroupKey:配置全局唯一标识服务分组的名称,比如,库存系统就是一个服务分
组。当我们监控时,相同分组的服务会聚合在一起,必填选项。
CommandKey:配置全局唯一标识服务的名称,比如,库存系统有一个获取库存服务,那么
就可以为这个服务起一个名字来唯一识别该服务,如果不配置,则默认是简单类名。
ThreadPoolKey:配置全局唯一标识线程池的名称,相同线程池名称的线程池是同一个,如
果不配置,则默认是分组名,此名字也是线程池中线程名字的前缀。
ThreadPoolProperties:配置线程池参数,coreSize配置核心线程池大小和线程池最大大
小,keepAliveTimeMinutes是线程池中空闲线程生存时间(如果不进行动态配置,那么是没
有任何作用的),maxQueueSize配置线程池队列最大大小,
queueSizeRejectionThreshold限定当前队列大小,即实际队列大小由这个参数决定,通过
改变queueSizeRejectionThreshold可以实现动态队列大小调整。
CommandProperties:配置该命令的一些参数,如executionIsolationStrategy配置执行隔
离策略,默认是使用线程隔离,此处我们配置为THREAD,即线程池隔离。
此处可以粗粒度实现隔离,也可以细粒度实现隔离,如下所示。
服务分组+线程池:粗粒度实现,一个服务分组/系统配置一个隔离线程池即可,不配置线
程池名称或者相同分组的线程池名称配置为一样。
服务分组+服务+线程池:细粒度实现,一个服务分组中的每一个服务配置一个隔离线程
池,为不同的命令实现配置不同的线程池名称即可。
混合实现:一个服务分组配置一个隔离线程池,然后对重要服务单独设置隔离线程池。本demo可以用Jmeter模拟多线程调用来验证结果,参看上课视频
那么,这个是Hystrix基于线程池+队列的方式实现的限流,当然,还有另外一种,基于信
号量来实现的。同学们知道什么是信号量把,说白了就是计数器。
当 计数器 + 1
> 设置的最大并发数 时,就限流,或者走降级渠道