熔断降级
在微服务项目中,一个微服务常常需要调用内部其他服务的接口,即便是单体架构项目,也难免会调用一些第三方API、访问数据库等。使用熔断降级功能可以有效避免因外部因素导致服务自身不可用甚至进程挂掉的情况发生。也许有些项目并不需要限流功能,但熔断降级功能却是微服务项目不可或缺的。
本篇学习Sentinel熔断降级的实现原理,主要内容包括以下几个方面:
旧版熔断降级。
新版熔断降级。
熔断器。
旧版熔断降级
如果想要实现限流功能,则需要根据不同的硬件条件做好压测,压测出一个接口或一个服务在固定的硬件配置下所能承受的最大QPS,然后根据QPS配置限流规则。在服务后期,需求可能会不断叠加,导致需要对接口重新做压测,或者根据线上的实际表现不断调整限流阈值,因此,限流功能可能很少被使用,或者限流阈值会被配置得比压测结果略大,这时就需要结合熔断降级做兜底容灾方案。
Sentinel支持对同一个资源配置多个相同类型或不同类型的限流规则,在配置了限流规则的基础上,还可以为同一资源配置熔断降级规则。在接口的QPS未达到限流阈值却已经有很多请求超时的情况下,就可能达到熔断降级规则配置的阈值,从而触发熔断,这就能很好地保护服务自身。
熔断降级规则
Sentinel围绕资源配置熔断降级规则,根据资源的实时指标数据与熔断降级规则实现熔断降级功能。
DegradeRule规则类的源码如下:
count:限流阈值。
timeWindow:重置熔断的窗口时间,默认值为0。
grade:熔断降级策略,支持按平均响应耗时(DEGRADE_GRADE_RT)、按失败比率(DEGRADE_GRADE_EXCEPTION_RATIO)和按失败次数(DEGRADE_GRADE_EXCEPTION_COUNT)3种熔断降级策略。
rtSlowRequestAmount:当熔断降级策略被配置为按平均响应耗时时,该值表示超过限流阈值的慢请求数量。
minRequestAmount:当熔断降级策略被配置为按失败比率时,该值表示可触发熔断的最小请求数。
passCount:非配置字段,只在熔断降级策略为按平均响应耗时时使用,用于累加慢请求数,该值由一个定时任务重置,周期为timeWindow(窗口时间大小)。
cut:非配置字段,用于记录当前是否已经触发熔断,当passCount的值大于或等于rtSlowRequestAmount的值时被设置为true,由定时任务在timeWindow之后被重置为false。
对于count,其对应的不同熔断降级策略代表不同的阈值,如异常比率阈值、异常总数阈值、慢请求总数阈值。
对于rtSlowRequestAmount,假设将该值配置为5,规则的阈值为100毫秒,当连续5个请求的计算平均耗时都超过100毫秒时,后面的请求才会被熔断,且在下个时间窗口恢复。
对于minRequestAmount,假设阈值配置为10,在第一个请求就失败的情况下,失败率为100%,而配置minRequestAmount可以避免这种情况的出现。
熔断降级的实现原理
DegradeSlot是实现熔断降级的切入点,作为ProcessorSlot被插入ProcessorSlotChain中,并在entry方法中调用Checker来判断是否熔断当前请求,若需要熔断当前请求,则抛出BlockException。
Checker并不是一个接口,而是一种check行为。限流的check行为由FlowRuleChecker实现,熔断的check行为则由DegradeRuleManager实现。在熔断降级中,真正的check行为的逻辑由DegradeRule实现。
熔断降级的check行为流程如图6.1所示:
图6.1 熔断降级的check行为流程
从图6.1可知,当DegradeSlot#entry方法被调用时,由DegradeSlot调用DegradeRuleManager#checkDegrade方法检查当前请求是否达到某个熔断降级规则配置的阈值。因为熔断降级规则配置由DegradeRuleManager加载,所以DegradeSlot将check行为的逻辑交给DegradeRuleManager完成。
DegradeRuleManager#checkDegrade方法的源码如下:
获取为当前资源配置的所有熔断降级规则。
遍历熔断降级规则,只要有一个熔断降级规则达到阈值,就抛出DegradeException。
DegradeRuleManager首先根据资源名称获取配置的熔断降级规则,然后遍历熔断降级规则,调用DegradeRule#passCheck方法将检查是否需要触发熔断的逻辑并交给DegradeRule完成。如果对一个资源配置多个熔断降级规则,则只要有一个熔断降级规则满足条件,就会触发熔断。
DegradeRule#passCheck方法的源码如下:
根据资源名称获取统计该资源全局指标数据的ClusterNode实例。
如果熔断降级策略为DEGRADE_GRADE_RT,则从ClusterNode实例中读取当前平均响应耗时,如果平均响应耗时小于阈值,则将慢请求计数器passCount重置为0,放行请求;
若平均响应耗时超过阈值,并且超过阈值的慢请求数累计值已经大于rtSlowRequestAmount的值,则熔断当前请求,见。
如果熔断降级策略为
DEGRADE_GRADE_EXCEPTION_RATIO,读取当前时间窗口的异常总数、成功总数和总请求数,若异常总数与成功总数的比值小于熔断降级规则配置的阈值,则放行请求;若异常总数与成功总数的比值大于或等于阈值,并且当前总请求数大于minRequestAmount,则熔断当前请求,见。
如果熔断降级策略为 DEGRADE_GRADE_EXCEPTION_COUNT,读取当前滑动窗口的异常总数,如果异常总数小于熔断降级规则配置的阈值,则放行请求,否则熔断当前请求,见。
更改熔断标志为true,使后续请求不需要重复判断,并且开启定时任务,用于重置熔断标志,在休眠timeWindow时长后重置熔断标志。
提示:当未配置或配置timeWindow为0时,cut被立即重置,也就是不保存熔断判断的结果,每个请求都需要重新判断一次,这会影响性能。
官方文档在介绍 DEGRADE_GRADE_EXCEPTION_COUNT 熔断降级策略的地方加了使用注意说明,内容为:“注意,由于统计时间窗口是分钟级别的,若timeWindow小于60秒,则结束熔断状态后仍可能再次进入熔断状态。”这句话并不难理解,因为调用ClusterNode实例的totalException方法获取的是1分钟内的总异常数。
ClusterNode类是StatisticNode类的子类。StatisticNode类的totalException方法的作用是从分钟级滑动窗口中获取异常总数,其源码如下:
正因如此,DEGRADE_GRADE_EXCEPTION_COUNT这个熔断降级策略的使用场景不多。由于timeWindow、passCount和cut是Sentinel出于性能考虑而添加的,在配置熔断规则时,建议不要将timeWindow配置为0或小于0,可以将timeWindow配置为1000毫秒,即一个时间窗口大小,因为能减少一点计算量就能降低一点Sentinel对应用性能的影响。
本文给大家讲解的内容是深度解析微服务高并发熔断降级 :旧版熔断降级
下篇文章给大家讲解的内容是深度解析微服务高并发熔断降级 :新版熔断降级
感谢大家的支持!
领取专属 10元无门槛券
私享最新 技术干货