AT 这种事务模式是阿里开源的seata主推的事务模式,本文会详解AT的原理,并将它与XA模式进行比拟
原理
AT 从原理下面看,与 XA 的设计有很多相近之处。XA 是数据库层面实现的二阶段提交, AT 则是利用/驱动层实现的二阶段提交。建议您理解了XA相干的常识后,来浏览这篇文章,这样可能更快更好的把握 AT 的原理与设计。
AT的角色和XA一样分为3个,然而起了不一样的名称,大家留神分辨:
- RM 资源管理器,是业务服务,负责本地数据库的治理,与XA中的RM统一
- TC 事务协调器,是Seata服务器,负责全局事务的状态治理,负责协调各个事务分支的执行,相当于XA中的TM
- TM 事务管理器,是业务服务,负责全局事务的发动,相当于XA中的APP
AT 的第一阶段为prepare,它在这一阶段会实现以下事件:
- RM 侧,用户开启本地事务
-
RM 侧,用户每进行一次业务数据批改,假如是一个update语句,那么 AT 会做以下内容:
- 依据update的条件,查问出批改前的数据,该数据称为BeforeImage
- 执行update语句,依据BeforeImage中的主键,查问出批改后的数据,该数据称为AfterImage
- 将BeforeImage和AfterImage保留到一张undolog表
- 将BeforeImage中的主键以及表名,该数据称为lockKey,记录下来,留待后续应用
-
RM 侧,用户提交本地事务时,AT 会做以下内容:
- 将2.4中记录的所有的lockKey,注册到 TC(即事务管理器seata)上
- 3.1中的注册解决会查看 TC 中,是否已存在抵触的主键+表名,如果有抵触,那么AT会睡眠期待后重试,没有抵触则保留
- 3.1胜利实现后,提交本地事务
如果 AT 的第一阶段所有分支都没有谬误,那么会进行第二阶段的commit,AT 会做以下内容:
- TC 会将以后这个全局事务所有相干的lockKey删除
- TC 告诉与以后这个全局事务相干的所有业务服务,告知全局事务已胜利,能够删除undolog中保留的数据
- RM 收到告诉后,删除undolog中的数据
如果 AT 的第一阶段有分支出错,那么会进行第二阶段的rollback,AT 会做以下内容:
- TC 告诉与以后这个全局事务相干的所有业务服务,告知全局事务失败,执行回滚
-
RM 收到告诉后,对本地数据的批改进行回滚,回滚原理如下:
- 从undolog中取出批改前后的BeforeImage和AfterImage
- 如果AfterImage与数据库中的以后记录校验统一,那么应用BeforeImage中的数据笼罩以后记录
- 如果AfterImage与数据库中的以后记录不统一,那么这个时候产生了脏回滚,此时须要人工染指解决
- TC 待全局事务所有的分支,都实现了回滚,TC 将此全局事务所有的lockKey删除
问题剖析
AT 模式的一个突出问题是rollback中2.3的脏回滚难以避免。以下步骤可能触发该脏回滚:
- 全局事务g1对数据行A1进行批改 v1 -> v2
- 另一个服务将对数据行A1进行批改 v2 -> v3
- 全局事务g1回滚,发现数据行A1的以后数据为v3,不等于AfterImage中的v2,回滚失败
这个脏回滚一旦产生,那么分布式事务框架没有方法保证数据的一致性了,必须要人工染指解决。想要防止脏回滚,须要把所有对这个表的写访问,都加上非凡解决(在Seata的Java客户端中,须要加上GlobalLock注解)。这种束缚对于一个上了肯定规模的简单零碎,是十分难以保障的。
AT vs XA
上述脏回滚问题,在 XA 事务中不会呈现,因为 XA 事务是在数据库层面实现的,当另一个服务对为数据行A1进行批改时,会因为行锁被阻塞,与一般事务的体现齐全一样,不会产生问题。
另外 XA 不会产生脏读,而 AT 会产生脏读,思考AT下的如下执行步骤:
- 全局事务g1对数据行A1进行批改 v1 -> v2
- 另一个服务将读取数据行A1,取得数据 v2
- 全局事务g1回滚,将数据行A1改回 v2 -> v1
MVCC
性能剖析
从原理的具体步骤看,XA事务的性能高于AT,剖析如下:
AT 模式下,RM侧,上述原理过程中,执行的SQL如下:
- 开启事务
- 查问BeforeImage数据
- 执行update
- 查问AfterImage数据
- 将BeforeImage,AfterImage插入到undolog中
- 提交事务
- 事务实现后,删除BeforeImage和AfterImage
而 XA 模式下,RM侧,执行的SQL如下:
- xa begin
- 执行update
- xa end
- xa prepare
- xa commit
两者比照,相干的开启/提交事务是两个模式都须要的,性能差别不大。然而从执行的DML操作来看,AT 下的 SQL 数量为:3 writes,2 read,比 XA 下仅一个update多出许多,因而在性能上会有较大的差距
从上述实践剖析,XA 事务性能会大幅高于AT,该当能够在postgres数据库上验证进去;而mysql数据库,在以后的5.8版本上,因为xa prepare后,须要将以后连贯断开才可能在其余连贯上xa commit,所以会有一个从新创立连贯的开销,最终性能比照参考下一节。
性能实测
上述进行了实践上的性能剖析,我同时也做了性能实测,具体的测试过程和后果数据,参考 xa-at bench
dtm实现的XA事务,为了在极其状况下,也能保障XA事务可能正确的被清理,会在业务事务中对子事务屏障表进行插入,因而会比上述实践剖析中,多一个sql写入。
咱们能够看到,最终的后果XA性能优于AT。如果将来Mysql欠缺了XA的实现,能够不必敞开以后连贯也可能容许其余连贯提交xa事务,那么XA的性能还可能晋升一大截。
AT的意义
mysql在版本5.6中,xa相干API存在bug。如果以后连贯在xa prepare之后,连贯断开,那么这个连贯未实现的事务会被主动回滚。这样的bug导致mysql的XA模式是无奈保障正确性的,在各种利用crash中,可能导致数据不统一。因而AT在mysql的5.6版本及更低版本应用中,是具备很高利用价值的。
另外局部大厂的数据库是禁止应用XA事务的,这种特定场景下,选型AT模式,也是正当的。
对于其余场景,倡议优先思考 XA 事务。
小结
作者对AT模式的残缺实现源码,并未残缺浏览。上述的相干原理是依据本人浏览相干材料,并参考了seata-golang的源代码而写。文中如果不精确之处,心愿各位读者帮忙斧正
欢送拜访 https://github.com/dtm-labs/dtm 并star反对咱们