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,它在这一阶段会实现以下事件:

  1. RM 侧,用户开启本地事务
  2. RM 侧,用户每进行一次业务数据批改,假如是一个update语句,那么 AT 会做以下内容:

    1. 依据update的条件,查问出批改前的数据,该数据称为BeforeImage
    2. 执行update语句,依据BeforeImage中的主键,查问出批改后的数据,该数据称为AfterImage
    3. 将BeforeImage和AfterImage保留到一张undolog表
    4. 将BeforeImage中的主键以及表名,该数据称为lockKey,记录下来,留待后续应用
  3. RM 侧,用户提交本地事务时,AT 会做以下内容:

    1. 将2.4中记录的所有的lockKey,注册到 TC(即事务管理器seata)上
    2. 3.1中的注册解决会查看 TC 中,是否已存在抵触的主键+表名,如果有抵触,那么AT会睡眠期待后重试,没有抵触则保留
    3. 3.1胜利实现后,提交本地事务

如果 AT 的第一阶段所有分支都没有谬误,那么会进行第二阶段的commit,AT 会做以下内容:

  1. TC 会将以后这个全局事务所有相干的lockKey删除
  2. TC 告诉与以后这个全局事务相干的所有业务服务,告知全局事务已胜利,能够删除undolog中保留的数据
  3. RM 收到告诉后,删除undolog中的数据

如果 AT 的第一阶段有分支出错,那么会进行第二阶段的rollback,AT 会做以下内容:

  1. TC 告诉与以后这个全局事务相干的所有业务服务,告知全局事务失败,执行回滚
  2. RM 收到告诉后,对本地数据的批改进行回滚,回滚原理如下:

    1. 从undolog中取出批改前后的BeforeImage和AfterImage
    2. 如果AfterImage与数据库中的以后记录校验统一,那么应用BeforeImage中的数据笼罩以后记录
    3. 如果AfterImage与数据库中的以后记录不统一,那么这个时候产生了脏回滚,此时须要人工染指解决
  3. TC 待全局事务所有的分支,都实现了回滚,TC 将此全局事务所有的lockKey删除

问题剖析

AT 模式的一个突出问题是rollback中2.3的脏回滚难以避免。以下步骤可能触发该脏回滚:

  1. 全局事务g1对数据行A1进行批改 v1 -> v2
  2. 另一个服务将对数据行A1进行批改 v2 -> v3
  3. 全局事务g1回滚,发现数据行A1的以后数据为v3,不等于AfterImage中的v2,回滚失败

这个脏回滚一旦产生,那么分布式事务框架没有方法保证数据的一致性了,必须要人工染指解决。想要防止脏回滚,须要把所有对这个表的写访问,都加上非凡解决(在Seata的Java客户端中,须要加上GlobalLock注解)。这种束缚对于一个上了肯定规模的简单零碎,是十分难以保障的。

AT vs XA

上述脏回滚问题,在 XA 事务中不会呈现,因为 XA 事务是在数据库层面实现的,当另一个服务对为数据行A1进行批改时,会因为行锁被阻塞,与一般事务的体现齐全一样,不会产生问题。

另外 XA 不会产生脏读,而 AT 会产生脏读,思考AT下的如下执行步骤:

  1. 全局事务g1对数据行A1进行批改 v1 -> v2
  2. 另一个服务将读取数据行A1,取得数据 v2
  3. 全局事务g1回滚,将数据行A1改回 v2 -> v1
MVCC

性能剖析

从原理的具体步骤看,XA事务的性能高于AT,剖析如下:

AT 模式下,RM侧,上述原理过程中,执行的SQL如下:

  1. 开启事务
  2. 查问BeforeImage数据
  3. 执行update
  4. 查问AfterImage数据
  5. 将BeforeImage,AfterImage插入到undolog中
  6. 提交事务
  7. 事务实现后,删除BeforeImage和AfterImage

而 XA 模式下,RM侧,执行的SQL如下:

  1. xa begin
  2. 执行update
  3. xa end
  4. xa prepare
  5. 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反对咱们