暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

GoldenDB的全局事务管理机制

乐呵呵 2024-06-11
306

现有的两阶段提交存在如下缺点:

(1)数据不一致。在提交阶段中,事务管理器向所有参与者发送提交请求后,由于网络延迟不同或者服务器处理速度不同,会出现部分参与者已经提交,部分参与者尚未提交的情况,在多个参与者提交的间隙会出现数据不一致的情况,出现脏读。

在上图的例子中,事务 T1 执行转账操作,从账户 1 转账 50 元到账户 2,在事务 T1 的

两阶段提交期间,若有事务 T2 读取账户 1 和账户 2 的余额之和,结果是 50+20=70,产生数据不一致问题。虽然这个时间间隙很短,发生的概率非常低,但在对数据一致性要求极高的金融交易中,任何不一致的情况都不允许发生。若在提交时发生了网络异常或者协调者发生了故障,也会导致整个分布式系统出现数据不一致性的现象,在系统故障恢复前,任何操作都会读取到不一致的数据。

(2)同步阻塞。在二阶段提交模型中,事务管理器记录了所有本地事务和全局事务的状态,它的角色至关重要,一旦它发生故障,参与者会一直阻塞下去。尤其在第二阶段开始前,若事务管理器发生故障,那么所有的参与者都处于阻塞状态。若在事务管理器发出提交消息之后宕机,且唯一接收到这条消息的参与者也同时宕机,那么这条事务的状态进入“悬挂”状态,无法确定是该提交还是回滚。在高并发的场景下,一旦出现同步阻塞,数据库会出现性能陡降。

(3)已提交数据无法回滚。在第二阶段中,如果个别参与者发生故障,事务管理器将尝试在此提交失败的数据库上重新提交,如果此节点一直不成功,则需要对于所有节点中已经提交数据要进行回滚,让数据回到交易前的状态,而单节点的数据库本身不能回滚已经提交的数据,只能由业务介入,通过补偿操作实现。在此种数据库上,每个业务都要准备相应的补偿业务来保证业务失败带来的数据不一致,工作量巨大,业务逻辑复杂起来,改造过于痛苦。

GoldenDB 中引入了全局事务管理器的设计,采用了改进的两阶段提交方式。在执行事务过程中,为每个事务分配一个全局事务 ID(GTID),通过 GTID 来实现事务一次提交成功。采用一阶段提交+补偿事务的方式,如果事务在提交阶段有部分节点提交失败,将回滚已成功提交的事务,而不是让失败的节点不断重试。与两阶段提交相比,一阶段提交减少了与数据节点的交互次数,降低了锁冲突概率,提升了事务处理效率。

基本原理如下:

1)建表时增加一个隐藏字段,用于记录 GTID。

2)每个分布式事务开始时,计算节点发送请求到全局事务管理器(以下简称 GTM)

为事务申请一个 GTID,GTID 是全局唯一且单调递增的整数,在 GTM 中使用散列结构存放;GTID 申请成功后至释放前,GoldenDB 称该 GTID 为活跃(active)状态,该 GTID 对应的事务状态为未提交状态;若涉及到数据更新,则将本次 GTID 更新到本事务将要更新的数据中;事务成功提交后,计算引擎发送请求 GTM 到将 GTID 释放,此时 GoldenDB 称GTID 为非活跃(inactive)状态,对应的事务状态为已提交状态。如下图:



事务对应的 GTID 同时记录在数据库日志中。当事务提交失败时,提交失败节点会自动回滚,对于已成功提交的节点,数据库根据本事务所对于的 GTID,从日志中捞对应的出执行成功的操作,生成反向操作语句将其回滚,将数据恢复到更新前的状态,全部节点回滚完成后,释放 GTID。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论