原创 吴就业 147 0 2020-09-22
本文为博主原创文章,未经博主允许不得转载。
本文链接:https://wujiuye.com/article/9be23d177a8f4f2db06d2560e813567a
作者:吴就业
链接:https://wujiuye.com/article/9be23d177a8f4f2db06d2560e813567a
来源:吴就业的网络日记
本文为博主原创文章,未经博主允许不得转载。
在本专栏写作完成之际,笔者看到阿里官方推出了Sentinel 1.8.0 版本,该版本发布时间为2020/08/20。
与此同时,官方文档也更新了关于熔断降级的介绍。
从官方文档来看,该版本的最大亮点是对熔断降级功能进行了重构。旧版本的熔断降级功能对慢调用并不友好,而新版本改善了这个问题。
在微服务项目中,一个微服务常常需要调用内部其它服务的接口,即便是单体架构项目,也免不了会调用一些第三方API、访问数据库,使用熔断降级功能可以有效避免外部因素导致服务自身不可用甚至进程挂掉的情况发生。也许我们项目并不需要限流,但熔断机制却是微服务项目不可或缺的降级方式。所以笔者决定,为专栏添加一篇文章,介绍新版本的熔断降级。
笔者在得知Sentinel更新1.8.0版本的第一时间就看了熔断降级重构后的源码,从源码对比新旧版本细节上的差异。
1.7.x版本支持三种熔断降级策略为:
按平均响应耗时,只支持统计时长为一秒钟,在接口耗时较长场景下导致统计的请求较为稀疏,熔断效果不佳。例如调用第三方支付接口,我们实际项目中统计平均耗时超过1秒。
在旧版本中,当选择DEGRADE_GRADE_RT策略时,阈值为平均响应耗时,如果一秒内的平均响应耗时超过规则配置的阈值,当连续rtSlowRequestAmount个请求之后,平均耗时依然超过阈值,则触发熔断,这导致平均响应耗时策略容易受某个特别慢的请求影响。
如某接口调用平均耗时正常为100ms,熔断阈值为500ms,假设一秒内10个请求,有一个请求耗时超过10秒,就会将平均响应耗时上升到1100ms,后续需要很多个请求的耗时为100ms才能将平均耗时降下来,很容易就超过rtSlowRequestAmount,导致熔断降级,这样的影响非常致命。
按失败比率,只支持统计时长为一秒钟,与按平均响应耗时一样,不适用于慢调用场景。
按失败次数,只支持统计时长为一分钟,即便timeWindow配置为1秒,在timeWindow秒之后关闭开关,开关也会立即被打开,所以大部分场景都使用不上,使其成为一个摆设功能。
1.8.0版本使用的熔断策略(CircuitBreakerStrategy):
DegradeRule类可配置字段如下:
public class DegradeRule extends AbstractRule {
private int grade;
private double count;
private int timeWindow;
private int minRequestAmount;
private double slowRatioThreshold = 1.0d;
private int statIntervalMs = 1000;
}
与旧版本的不同:
DegradeRule的statIntervalMs字段用于指定指标数据统计时长,单位为毫秒,默认值为1000。
例如某接口平均耗时为1秒,则统计时长可配置为10秒,通过延长统计时长,将稀疏请求调整为“密集”请求。
由旧版本的按平均响应耗时策略改为按慢请求比率策略,统计慢请求数,使用慢请求数与总请求数的比值与阈值比较。
当熔断策略为SLOW_REQUEST_RATIO时:
1.8.0版本开始,Sentinel使用熔断器实现熔断降级功能,每个熔断降级规则对应生成一个熔断器,为熔断器引入半开启状态,并可注册自定义事件监听器以感知熔断器的状态变化。
熔断器有三种状态:开启状态、半开启状态和关闭状态。
熔断器的状态改变有点类似于线程的状态改变,因此笔者将熔断器的改变条件绘制成下图。
一开始熔断器的状态为关闭状态,在达到熔断降级规则的阈值时,熔断器的状态从关闭变为开启状态。
熔断器不能直接从开启状态变为关闭状态,只能处在半开启状态的熔断器才能关闭。当熔断器从关闭状态变为开启状态的时间与当前时间的间隔超过timeWindow时,尝试将熔断器变为半开启状态。
熔断器可以从半开启状态变为关闭状态,也可以从半开启状态变为开启状态。
触发熔断器从半开启状态变为开启状态的时机有两个:
处理半开启状态的熔断器,只要当前请求调用正常,即可关闭:
在状态改变的过程中会通知监听器,同时也会修改一些数据,如下图所示。
熔断器状态从关闭到开启:更新下一次允许将熔断器关闭的时间,即间隔timeWindow秒之后才可以将熔断器关闭。
熔断器状态从半开启状态到打开状态:更新下一次允许熔断器关闭的时间。如果熔断器刚从开启状态变为半开状态,此时想尝试关闭却发现又达到阈值了,那么就恢复为开启状态,并延长timeWindow之后再重试关闭。
熔断器状态从半开启状态到关闭状态:重置当前时间窗口的bucket,由于只有一个bucket,所以是重置整个滑动窗口。重置统计的指标数据是避免熔断器刚关闭又立即进入开启状态。
从新旧版本对比也能看出,新版本对熔断降级功能的改动很大。特别是加入了半开启自动恢复支持,旧版本需要通过定时器来重置熔断状态,而新版中引入熔断器和三种状态,巧妙的实现了熔断器自动开启和自动关闭的功能。
虽然我们没有分析源码,但这却是笔者看了源码之后总结出来的,如果你想要了解源码,看完本篇后再去看源码,你的思路会清晰很多。建议看完源码之后看下这个Issue:https://github.com/alibaba/Sentinel/issues/1638
,了解为什么当请求被其它地方拒绝时或者被其他熔断器拒绝时将熔断器打开。关于半开启自动恢复的介绍:https://martinfowler.com/bliki/CircuitBreaker.html
。
如果你们项目也使用了Sentinel的熔断降级功能,笔者强烈推荐你们升级一下Sentinel版本,以获取更好的熔断降级效果。
声明:公众号、CSDN、掘金的曾用名:“Java艺术”,因此您可能看到一些早期的文章的图片有“Java艺术”的水印。
本篇内容介绍如何使用r2dbc-mysql驱动程序包与mysql数据库建立连接、使用r2dbc-pool获取数据库连接、Spring-Data-R2DBC增删改查API、事务的使用,以及R2DBC Repository。
消息推送服务主要是处理同步给用户推送短信通知或是异步推送短信通知、微信模板消息通知等。本篇介绍如何使用Spring WebFlux + R2DBC搭建消息推送服务。
IDEA有着极强的扩展功能,它提供插件扩展支持,让开发者能够参与到IDEA生态建设中,为更多开发者提供便利、提高开发效率。我们常用的插件有Lombok、Mybatis插件,这些插件都大大提高了我们的开发效率。即便IDEA功能已经很强大,并且也已有很多的插件,但也不可能面面俱到,有时候我们需要自给自足。
Instrumentation之所以难驾驭,在于需要了解Java类加载机制以及字节码,一不小心就能遇到各种陌生的Exception。笔者在实现Java探针时就踩过不少坑,其中一类就是类加载相关的问题,也是本篇所要跟大家分享的。
订阅
订阅新文章发布通知吧,不错过精彩内容!
输入邮箱,提交后我们会给您发送一封邮件,您需点击邮件中的链接完成订阅设置。