https://windmt.com/2018/04/15/spring-cloud-4-hystrix/
服务雪崩的每个阶段都可能由不同的原因造成,比如造成 服务不可用的原因有:
1,硬件故障
2,程序Bug
3, 缓存击穿
4,用户大量请求
硬件故障可能为硬件损坏造成的服务器主机宕机,网络硬件故障造成的服务提供ing者不可访问。
缓存击穿一般发生在缓存应用重启,所有缓存被清空事,以及短时间大量的缓存数据失效时。大量的缓存不命中,使得大量的请求直击后端,造成服务提供者超负荷运行,引起服务不可用。
在秒杀和大促开始前,如果准备不充分,用户发起大量请求也会造成服务提供者的不可用。
而形成 重试加大流量的原因有:
用户重试
代码逻辑重试
在服务提供者不可用后,由于用户忍受不了界面上长时间的等待,而不断刷新页面甚至提交表单,服务调用端的会存在大量服务异常后的重试逻辑。
这些重试都会进一步加大请求流量
最后,服务调用者不可用产生的主要原因是:
同步等待造成的资源耗尽
当服务调用者使用同步调用时,会产生大量的等待线程占用系统资源。一旦系统资源被耗尽,服务调用者提供的服务也将处于不可用状态,于是服务雪崩效应产生了。
应对策略
针对造成服务雪崩的不同原因,可以使用不同的应对策略
1.流量控制
2,改进缓存模式
3,服务自动扩容
4,服务调用者降级服务
流量控制 的具体措施包括:
网关限流
用户交互限流
关闭重试
因为nginx 的高性能,目前一线互联网公司大量采用Nginx+Lua 的网关进行流量控制,由此而来的OpenResty 也越来越热门
用户交互限流的具体措施有: 1 采用加载动画,提高用户的忍耐等待时间,2,提交按钮添加强制等待时间机制
改进缓存模式的措施包括:
缓存预加载
同步改为异步刷新
服务自动扩容的措施主要包括
AWS 的 auto scaling
服务调用者降级服务的措施包括:
资源隔离
对依赖服务分类
不可用服务的代用快速失败
资源隔离主要是对调用服务的线程池进行隔离:
我们根据具体服务,将依赖服务分为:强依赖和弱依赖,强依赖服务不可用会导致当前业务终止,而弱依赖服务的不可用不会导致当前业务的终止
不可用服务的调用快速失败一般通过 超时机制,熔断器 和熔断后的降级方法来实现。
使用Hystrix预防服务雪崩
对于查询操作,我们可以实现一个fallback方法,当请求后端的服务出现异常的情况的时候,可以使用fallback 方法返回值。fallback 方法的返回值一般是设置的默认值或者来自缓存。
资源隔离:
货船为了进行防止漏水和火灾的扩散,会将货仓分隔为多个,如下图所示:
这种资源隔离减少风险的方式呗称为: Bulkheads(舱壁隔离模式)
hystrix 将同样的模式运用到了服务调用者上
在hystrix 中。主要通过线程池来实现资源隔离。通常在使用的时候我们会根据调用的远程服务划分出多个线程池。例如调用那个产品服务的Command 放入A线程池,调用账户服务的Command 放入B 线程池 ,这样做的主要优点是运行环境被隔离开了。这样就算调用服务的代码存在bug 或者由于其他的原因导致自己搜子啊的线程池被耗尽时,不会对系统的其他的服务造成影响。
通过依赖服务的线程池隔离实现,可以带来如下优势:
应用自身得到完全的保护,不会受不可控的依赖服务影响,即便给依赖服务分配的线程池填满,也不会影响自身的其余部分。
可以有效的降低介入新服务的风险。如果新服务接入后运行不稳定或存在问题,完全不会影响到应用其他的请求。
当依赖的服务从失效恢复正常后,他的线程池会被清理并且马上能够恢复健康的服务,相比之下容器的级别的清理恢复速度要慢好多。
当依赖的服务出现配置错误时候,线程池会快速的反映出此问题(通过失败次数,延迟,超时,拒绝等指标的增加情况)。同时,我们可以在不影响应用功能的情况下通过实时的动态属性刷新(后续会通过Spring Cloud Config 与 Spring Cloud Bus 的联合使用来介绍)来处理他
当依赖的服务因实现机制调整等原因造成其性能出现很大变化的时候,次数线程池的监控指标信息会反映出这样的变化。同时,我们也可以通过实时动态刷新自身应用对依赖服务的阀值进行调整以适应依赖方的改变。
除了上面通过线程池隔离服务发挥的优点之外,每个专有的线程池都提供了内置的并发实现。可以利用它为同步的依赖服务构建异步的访问
总之,通过对依赖服务实现线程池隔离,让我们应用更加健壮,不会因为个别依赖服务出现问题而引起相关的异常。同时,也使得我们的应用变动更加灵活,可以在不停止服务的情况下,配合动态配置刷新实现性能配置上的调整。
虽然线程池隔离的方案带来了好多好处,但是很多使用者可能胡担心为为一个依赖服务都分配一个线程池是否会过多的增加系统的负载和开销。对于这一点,使用者不用过于担心,因为这些顾虑也是大部分工程师们会考虑的,Netflix在设计Hystrix的时候,认为线程池上的开销相对于隔离所带来的好处是无法比拟的。同时,Netflix 也针对线程池的开销做了相关的测试。以证明和打消Hystrix 实现低性能影响的顾虑。
夏敏时候 Netflix Hystrix 官方提供的一个Hystrix 命令的性能监控,该命令以每秒60个请求的速度(QPS) 像一个单服务实例 进行访问,该服务实例每秒运行的线程数峰值为350
断路器模式
断路器模式来源于 Martin Fowler的 CircuitnBreaker 一文。 “断路器””本身是一种开关装置,用于在电路上保护线路过载。当线路中有电器发生短路时,“断路器” 能够及时的切断故障电路,防止发生过载,发热,甚至起火等严重后果。
在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),直接切断原来的主逻辑调用。但是,在Hystrix 中的断路器除了切断主逻辑的功能之外,还有更复杂的逻辑,下面我们来看看他更为深层次的处理逻辑。
断路器开关相互转换的逻辑如下图:
当Hystrix Command 请求后端服务失败数量超过一定的阀值,断路器会切换到开路状态(Open),这时候所有的请求会直接失败而不会
发送到后端服务。
这个阀值涉及到三个重要的参数: 快照时间窗,请求总数下限,错误百分比下限。这个参数的作用分别是:
快照时间窗: 断路器确定是否打开需要统计一些请求和错误数据,,而统计的时间范围就是快照的时间窗,默认为最近的10秒
请求总数下限: 在快照时间窗内,必须满足请求总数下限才有资格进行熔断。默认为20,意味着10秒内。如果该Hystrix Command 的调用此时不足20次,即时所有的请求都超时或者其他原因失败,断路器都不会打开。
错误百分比下限,当请求总数在快照时间窗内超过了下限,比如发生了30次调用,如果在30次调用中,有16次发生了超时异常,也就是超过了50%的错误百分比,在默认设定50%下限的情况下,这时就会将 断路器打开。
断路器保持在开路状态下一段时间后(默认5秒),自动切换到半开路状态(HALF-OPEN).这时会判断下一次请求的返回情况,如果请求成功,断路器切回闭路状态(CLOSED),否则重新切换到开路状态(OPEN)