在上一篇博客seata注解@GlobalTransactional原理探究中我们会看到一些关于降级相关的配置项, 抱着一探究竟的态度, 这篇聊一聊这个seata中的降级策略
官方解释
先看一下官方文档中相关的三个参数以及对该策略的具体解释
官方文档地址:
https://seata.apache.org/zh-cn/docs/v1.3/user/configurations
关于服务自动降级策略的具体实现介绍:
通过读取client.tm.degradeCheck是否为true,决定是否开启自检线程.
随后读取degradeCheckAllowTimes和degradeCheckPeriod,确认阈值与自检周期.
举个例子:
假设degradeCheckAllowTimes=10,degradeCheckPeriod=2000
那么每2秒钟会进行一个begin,commit的测试,如果失败,则记录连续失败数,如果成功则清空连续失败数.连续错误由用户接口及自检线程进行累计,直到连续失败次数达到用户的阈值,则关闭Seata分布式事务,避免用户自身业务长时间不可用.
反之,假如当前分布式事务关闭,那么自检线程继续按照2秒一次的自检,直到连续成功数达到用户设置的阈值,那么Seata分布式事务将恢复使用
接下来深入源码看一下是怎么实现的? 还是GlobalTransactionScanner
这个类
构造器
if (degradeCheck) {
// 加入一个配置变化监听器, 由于GlobalTransactionScanner本身实现了ConfigurationChangeListener, 所以这里的this就是一个监听器
ConfigurationCache.addConfigListener(ConfigurationKeys.CLIENT_DEGRADE_CHECK, this);
// 获取degradeCheckPeriod和degradeCheckAllowTimes这两个配置项的值
degradeCheckPeriod = ConfigurationFactory.getInstance().getInt(
ConfigurationKeys.CLIENT_DEGRADE_CHECK_PERIOD, DEFAULT_TM_DEGRADE_CHECK_PERIOD);
degradeCheckAllowTimes = ConfigurationFactory.getInstance().getInt(
ConfigurationKeys.CLIENT_DEGRADE_CHECK_ALLOW_TIMES, DEFAULT_TM_DEGRADE_CHECK_ALLOW_TIMES);
// 这里EVENT_BUS使用的是guava的工具类EventBus, 将自己注册为订阅者, 也就是说当发布了订阅的事件, 就会对应的执行逻辑
EVENT_BUS.register(this);
// 如果两个配置项均大于0, 则开启降级检查
if (degradeCheckPeriod > 0 && degradeCheckAllowTimes > 0) {
startDegradeCheck();
}
}
下面分别看一下对于Guava的事件监听逻辑是什么
以及startDegradeCheck
具体做的事情
Guava的事件监听
由于是将当前对象注册为了订阅者, 那么当前类中肯定有对应的事件监听逻辑, 就这样我们找到了这个方法
开始方法之前先解释一下degradeNum和reachNum这两个值啊, 看过上面官方文档中对降级策略的解释, 大家应该知道, 降级是因为请求失败的次数到达阈值, 然后关闭了分布式事务; 但是如果当前分布式事务是关闭的则还会继续检测直到成功的次数也到达阈值才恢复分布式事务; 这里degradeNum就是失败次数, reachNum就是成功的次数
@Subscribe
public static void onDegradeCheck(DegradeCheckEvent event) { // 监听的是DegradeCheckEvent事件
// 1. 请求success的情况
if (event.isRequestSuccess()) {
// 如果degradeNum已经到达阈值, 则说明当前分布式事务是关闭的, 那么reachNum肯定要加1
if (degradeNum >= degradeCheckAllowTimes) {
reachNum++;
// 这个时候如果成功的次数也到达了阈值, 那么就能恢复分布式事务了, 这时就将degradeNum和reachNum都清0
if (reachNum >= degradeCheckAllowTimes) {
reachNum = 0;
degradeNum = 0;
if (LOGGER.isInfoEnabled()) {
LOGGER.info("the current global transaction has been restored");
}
}
}
// 如果degradeNum没有到达阈值, 直接将degradeNum清0, 因为这次成功了, 失败的次数没有累积到阈值
else if (degradeNum != 0) {
degradeNum = 0;
}
}
// 2. 请求失败的情况
else {
// 如果degradeNum没到达阈值, , degradeNum加1
if (degradeNum < degradeCheckAllowTimes) {
degradeNum++;
// degradeNum加1之后如果已经到达阈值, 这时符合自动降级的策略了, 分布式事务要关闭
if (degradeNum >= degradeCheckAllowTimes) {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn("the current global transaction has been automatically downgraded");
}
}
}
// 如果degradeNum已经到达阈值并且reachNum不等于0, 则将reachNum清0, 这里也很好理解啊, 大家试着理解一下
else if (reachNum != 0) {
reachNum = 0;
}
}
}
startDegradeCheck方法
startDegradeCheck方法就比较简单了, 就是开启了周期任务执行begin和commit
, 然后看成功还是失败, 大家自己看一下吧, 我就不赘述了
private static void startDegradeCheck() {
executor.scheduleAtFixedRate(() -> {
if (degradeCheck) {
try {
String xid = TransactionManagerHolder.get().begin(null, null, "degradeCheck", 60000);
TransactionManagerHolder.get().commit(xid);
EVENT_BUS.post(new DegradeCheckEvent(true));
} catch (Exception e) {
EVENT_BUS.post(new DegradeCheckEvent(false));
}
}
}, degradeCheckPeriod, degradeCheckPeriod, TimeUnit.MILLISECONDS);
}
降级到底是怎么执行的?
通过上面的源码分析, 大家应该明白了降级策略的流程, 但是不知道大家注意到没有, 上面光是对degradeNum
的数值就行了处理, 并且打印了日志, 日志里说我要降级了
, 然后就没了, 玩呢? 说降级就是降级了啊; 哈哈, 不闹了, 大家还记得上一篇博客seata注解@GlobalTransactional原理探究中分析执行流程的invoke方法吗, 贴一下
好了好了, 先到这了, 下次再见