请回答事务(3)-XA、AT、TCC

745 阅读7分钟

一、XA

XA 规范是国际开放标准组织Open Group 关于分布式事务处理(DTP)的规范。规范描述了全局的事务管理器与局部的资源管理器之间的接口。XA规范的目的是允许多个资源(如数据库、应用服务器、消息队列等)在同一事务中访问,这样可以使ACID属性跨越应用程序而保持有效。XA使用两阶段提交来保证所有资源同时提交或回滚任何特定的事务。

XA规范描述了资源管理器要支持事务性访问锁必须做的事情,遵守该规范的资源管理器被称为 XA compliant

角色

  • AP(Application Program):应用程序,可以理解为使用分布式事务的程序
  • RM(Resource Manager):资源管理器,可以理解为事务的参与者,一般情况下是指一个数据库实例,通过资源管理器对该数据库进行控制,资源管理器控制着分支事务
  • TM(Transaction Manager):事务管理器,可以理解为协调者,负责协调和管理事务。事务管理器控制着全局事务,管理事务生命周期,并协调各个RM。全局事务是指分布式事务处理环境中,需要操作多个数据库共同完成一个工作,这个工作即是一个全局事务。

DTP 模型定义 TM 和 RM 之间通讯的接口规范叫做 XA,简单理解为数据库提供的2PC接口协议,基于数据库的XA协议来实现的2PC又称为XA方案。

所以 XA 方案可以看做是 2PC 的一种实现,其原理其实就是 2PC

二、AT

可以参考下 Seata 是什么 中的文档,讲的非常详细细致。

整体的流程在官方文档中没有找到,可以参考这张图:

要注意的是第10步,在判断可以提交事务之后,为什么是先释放全局锁再提交分支事务呢?

因为分支事务实际上在第一阶段已经提交完了,这一步主要是告诉分支事务,可以进行第二阶段的“提交”了,只是这个提交并非是提交本地事务,而是清楚 undolog。

适用场景分析:

SeataAT 模式是在本地事务的基础上增加了全局锁,锁的机制保证了很好的隔离性,但也降低了事务的并发性能。AT 模式的最大优势就是对业务的无侵入,分布式事务是在框架层自动完成的,所以几乎没有改造成本。但是AT模式要求每个事务的参与者都有对应的关系型数据库,这也限制了他的应用场景。

这也是为什么本次我为审核中心接入分布式事务时没有选择AT的原因。因为下游会涉及到使用 MongoDB的存储、MQ等

综上,AT 模式比较适用于对隔离性和业务改造成本要求比较高的场景,但 AT 模式的应用场景比较局限,所有事务参与者必须有关系型数据库作为存储层。

三、TCC

TCC(Try Confirm Cancel)模式是由Pat Helland 于2007年发表的一篇名为《Life byond Distributed Transaction: as Apostate's Opinion》的论文提出,蚂蚁金服团队2019年在Seata开源软件v0.4.0版本中贡献的一种TCC分布式事务的实现方式

TCC 本质上是个业务层面上的2PC,是应用层面的2PC编程模型。它要求业务在使用 TCC 模式时必须实现三个接口Try()、Confirm()、Cancel()。

2PC 在面对故障时是非常脆弱的,尤其是:当参与者向prepare请求回复yes后,需要无限等待协调者的commit/abort消息,若此时协调者或其它参与者需要关机较长时间,那么该参与者也会在一段时间内不可用。

一、步骤

1.1 Try 阶段

完成所有的业务检查(一致性),预留业务资源(准隔离性)。所有的资源提供者预留都成功,try 阶段才能成功。

1.2 Confirm 阶段

确认执行业务操作,不做任何业务检查,只使用Try阶段预留的业务资源。

1.3 Cancel 阶段

取消Try阶段预留的业务资源。如果某个业务方的业务资源没有预留成功,则取消所有业务资源预留请求。

对于每个业务都需要实现3个接口,对应3个阶段

1.4 举例

暂时无法在飞书文档外展示此内容

1.5 小结

TCC 在try阶段只是锁定了资源,真正执行业务逻辑是在confirm阶段。所以try+confirm对应一个完全的业务逻辑。

TCC 整体流程比较简单,其难点在于业务上的定义,即对于每一个操作都需要定义三个动作分别对应 try-confirm-cancel。

因此 TCC 对业务的侵入较大和业务紧耦合,需要根据特定的场景和业务逻辑来设计相应的动作。还有一点要注意,撤销和确认操作的执行可能需要重试,因此还需要保证操作的幂等。

相对于2PC、3PC,TCC使用的范围更大,但是开发量也更大,毕竟都在业务上实现,但有时候这三个方法也不好写。由于TCC是在业务上实现的,所以它可以跨数据库、跨不同的业务系统来实现事务。

库存的 WithholdStock、ReduceStock、ReleaseStock 也是类似于这种思想,其对应的正是 try, confirm,cancel 三个方法

二、设计要点

上面主要从流程上讲述了 TCC 的具体执行步骤,接下来我们从具体场景入手,剖析下TCC在实现时有哪些需要注意的地方。

2.1 空回滚

如果协调者的 try() 请求因为网络超时失败,那么协调者在阶段二会发送 cancel() 请求。而这时这个事务参与者实际上之前并没有执行 try() 操作而直接收到了 cancel() 请求。

针对这个问题,TCC模式要求在这种情况下的 cancel 能直接返回成功,也就是要允许空回滚。

即接口设计时需要考虑到,cancel 接口如何识别该请求所指向的事务之前执行过 try 请求

2.2 防悬挂

接着上面的场景。try() 超时,事务参与者收到 cancel() 请求而执行了空回滚,但就在这之后网络恢复正常,事务参与者又收到了这个 try()。我们称此时 try() 和 cancel() 发生了悬挂,即先执行了 cancel 后又执行了 try。

针对这个问题,TCC模式要求在这种情况下,事务参与者要记录下 cancel 的事务ID,当发现 try() 的事务ID已经被回滚,则直接忽略掉该请求。因为这是一个永远不会走到 confirm() 阶段的 try() 请求(已经过期的 try()请求)。

2.3 幂等性

Confirm 和 cancel 的实现必须是幂等的。当这两个操作执行失败时协调者会发起重试。

三、适用场景

TCC 模式是一个应用层面的2PC,锁的粒度可以由业务根据场景自己处理,所以TCC模式的并发性能比较高。

因为TCC模式在准备阶段将全局资源进行了锁定,所以TCC的事务隔离级别是读已提交。

TCC 模式需要业务方实现 try()、confirm()和cancel() 三个接口,并且后两个接口必须幂等。并且要考虑到如果将一个业务逻辑拆分成 try 和 confirm 两个操作,所以相对来说对于业务接入有一定改造成本。

综上,TCC模式比较适用于对事务的并发性能和隔离级别要求比较高的场景,比如金融系统/支付系统

最后

  • 如果觉得有收获,三连支持下;
  • 文章若有错误,欢迎评论留言指出,也欢迎转载,转载请注明出处;
  • 个人vx:Listener27, 交流技术、面试、学习资料、帮助一线互联网大厂内推等

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿