写点什么

TIKV 分布式事务的异常处理逻辑

  • 2024-05-03
    北京
  • 本文字数:1776 字

    阅读完需:约 6 分钟

作者: Lystorm 原文来源:https://tidb.net/blog/66e7400e


在之前发表的一篇文章中,介绍了TIKV 分布式事务 ,这篇文章会接着上一篇文章,介绍一下分布式事务在节点出现异常时候的处理逻辑,与上一篇文档的目的一样,依然是希望分享出来让大家给看看我对这些逻辑的理解是不是存在偏差。


分布式事务的基本要素里,事务的原子性和一致性,在分布式集群中存在节点宕机的情况时,就无法保证,因此 TIKV 的分布式事务实现,使用了 2PC。也就是之前介绍的 prewrite 和 commit 两个步骤。实际生产中,可能会出现下表所示的这些异常情况。



逐条介绍一下这些异常,首先是 prewrite 阶段下的异常,prewrite 阶段,首先会对 primary key 进行操作,当操作失败, 失败原因可能是锁被占用或者超时或者是 leader 节点挂死,此时 secondary key 还未进行,那么所有的事务会直接进行回滚,因为所有操作都没有进行,这种异常对整体的影响比较小。


        场景二中,当 primary key 写入成功后,secondary key 执行命令也未发出,此时 leader 节点挂死,集群会等待节点恢复,集群中会存在两个计时器,一个是 follow 节点的 leader 节点心跳计时器,还一个是锁的超时计时器,因为随机时间的存在,这两个超时器无法确定谁先到达阀值,因此接下来会出现以下几种情况:


①节点正常恢复,恢复时不存在定时器超时,则继续后续的流程


②follow 节点的 leader 心跳计时器超时,触发新一任 leader 选举,此时可以认为 primary key 写入失败,所有节点回滚;


③节点正常恢复,未触发选举超时,但是锁的超时计时器已到达阀值,primary key 已超时被释放了,也就是写入失败了,所有节点回滚;


        场景三的情况与场景二类似,只不过 primary key 已经写入成功,并且 secondary key 也开始进行上锁的过程,但是此时 primary key 挂死了,最终的异常判断逻辑还是会和场景二一样。


        场景四是 primary key 写入成功,且节点后续无异常,异常出现在 secondary key 写入的过程,因为事务的原子性,只要存在失败项,则会触发所有节点的回滚。


        场景五开始,prewrite 阶段已完成,开始进入 commit 阶段的异常情况。primary key 提交失败,会直接触发所有节点的回滚,secondary key 涉及到的行 commit 会在 primary key 提交完毕后才会进行,但是 Lock CF 与 Default CF 中的内容其实全部都已经完成了,commit 阶段的回滚,对集群整体的影响是很大的。


        场景六,primary key 提交成功了,但是在对 primary key 进行锁释放操作时节点挂死,导致 primary key 无法及时释放,此时后续的流程会阻塞,类似于场景二,需要等待节点的恢复,再根据是否恢复以及恢复时的计时器是否存在超时,判断 primary key 事务的提交及锁释放是否成功,若成功,则意味着整体事务已完成,secondary key 涉及的行的 commit 操作会异步开始进行。


        场景七,该场景是实际生产中出现的比较多的异常场景,因为只要 primary key 提交成功,且锁已经释放了,就认为此次的写入成功了,其余的锁其实是以指针的形式指向主锁,主锁释放了,其余的副锁相当于也释放了。只不过需要先对数据写入到 write CF 中,然后再释放掉锁,只要主锁完成了释放,剩下的过程都是异步进行的,如果涉及到的数据很大,那这个过程可能需要较长的时间,在这过程中,不管是 leader 节点还是 follow 节点,都可能会出现异常。


        场景七中,当 leader 节点发生异常,后续恢复时,如果集群中存在新的 leader 节点,那么会转变自己的角色,然后根据 leader 节点发送心跳中的 lastIndex,commitIndex 等信息来继续执行之前的事务,follow 节点发生异常,逻辑与 leader 节点相同,只不过不需要转变角色。下图是一个示例



TIKV Node1 在事务进行到绿色箭头所示的位置时,节点异常,恢复时,会接收到 leader 节点的心跳,发现自己的状态与 leader 节点不同步了,处理也是按照顺序进行,绿色箭头处可以看到 key=1 且 start_ta=110 处的 Lock CF 中有一把指向主锁的副锁,此时根据这个指向,去查看这把主锁的状态,红色箭头处可以看到这把主锁已经释放了,那副锁就知道此时自己应该完成 commit 操作,然后根据主锁的信息,更新自己的 commit_ts 信息,后面的行也是相同的逻辑,最终会同步到与 Node0 一样的状态,实现事务的一致性,如下图所示



至此结束!


发布于: 刚刚阅读数: 5
用户头像

TiDB 社区官网:https://tidb.net/ 2021-12-15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
TIKV分布式事务的异常处理逻辑_TiKV 底层架构_TiDB 社区干货传送门_InfoQ写作社区