分布式事务2PC TCC AT(Seata)如何理解AT模式
名词:
- TC 事务协调者
- TM 事务管理器
- RM 资源管理器
2PC 二阶段提交(Two-phaseCommit)
TC 给每个参与者发送预备请求,每个参与者要么能成功,要么不能成功,你要返回给TC,如果收到了每个参与者的成功消息,那么就发出commit指令,否则发送rollback。
这种方式最怕的就是其中一方由于网络延迟,卡顿等等造成让TC不知道是成功还是失败,这时候就会等待,而等待过程中,如果没有让参与者完成commit或rollback,那么就持续占有资源,直到完成。
XA协议采用两阶段提交方式来管理分布式事务。XA接口提供资源管理器与事务管理器之间进行通信的标准接口。XA协议包括两套函数,以xa_开头的及以ax_开头的。注意XA是已经实现2PC理论的协议,XA是XA,2PC是2PC,就和IOC和IOC容器的区别一样。
Atomikos jta的分布式事务是针对不同数据源的事务,但事务管理必须在一个服务中,虽然也支持Rest的调用方式,但是比较复杂。下面要说的分布式事务是服务和数据源全部分开。
TCC
TCC分为3个阶段,Try,Commit,Cancle,Try阶段尝试是否能执行成功,如果可以就执行commit,否则rollback,需要业务提供这些方法实现,开发成本高。
具体实现:
每个表需要增加本地log表,如try commit cancle表,为了什么呢?
- 防止空回滚
- 防止悬挂(重复的try)
- 幂等校验
try阶段先要判断是否已经被存在try commit cancle log中,如果存在,直接返回,为了上面那3点,需要有判断。然后扣减库存等等,如果执行成功添加到本地try_log表,然后调用上游服务,注意TCC事务发起者不要先去调用增加库存、金额等服务,因为这很可能造成无法回滚,在你增加的一瞬间被消费掉。
commit 阶段 不做事,只增加日志
cancle 阶段,同样先做幂等判断,然后执行回滚操作,回滚操作的原理就是根据try阶段进行反向操作,也就是事务补偿。
上面是下游服务tcc阶段,上游服务是try只增加日志,commit正式增加,cancle同样是反向操作。
有些有冻结字段的,原理相同,就是commit阶段改为正式更新。
为什么开发成本高,就是因为完完全全侵入到业务层,整体由应用控制。
Seata
Seata
原名Fescar
,目前版本已经在生产模式下使用。
这里主要介绍Seata
的AT
模式,Seata
同样支持TCC
等其他方式,他的TCC
用法和Hmily
差不多,只是注解接口名称不同罢了。
AT模式 (AsyncTransaction)
两阶段提交协议的演变:
- 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
- 二阶段:
提交异步化,非常快速地完成。
回滚通过一阶段的回滚日志进行反向补偿。
上面是seata
官网的原话,什么意思呢?就是以前的2PC是整个事务过程中,只要不提交或回滚,就持续占有锁资源,而seata
是异步方式
,直接本地执行或回滚,本地事务提交前,先拿到该记录的 全局锁,本地提交释放本地锁,完全不需要去等其他业务一起commit
,因为有Seata
来管理这些,他会从log
中判断是否回滚,如果回滚,根据日志执行事务补偿
。
如何理解AT模式
说一下个人见解,他算是2PC变种
,借鉴了TCC的方式
(不去长时间占用锁),锁占有的粒度细
了,并发就变高了。TCC
我们是手动实现TRY,COMMIT和CANCLE
,而seata
是靠它的代理数据源
将我们的事务ID,分支ID,与锁记录保存到它的数据库
,并且将我们的数据副本
保存到undo_log表(我们自己业务库中)
,这是为了变相实现数据库中的事务机制
,只是不去持续占有锁和手动的实现TCC
了,但是这样做的代价和TCC
相同,伪事务
,没有强一致性
,它有的只是最终一致性
。
在它的数据库中有global_table
、branch_table
、lock_table
,这3个表在seata服务端
,全局表,分支表和锁表,看名字都应该清楚了,具体结构和作用自己搭一下下断看一眼应该就明白,主要的是在你的业务数据库
中seata
要求建立一个undo_log
表,既然有记录,在回滚时seata
就会通过log
去执行事务补偿
,你可以理解为seata
帮我们完成了TCC
的操作,既然是这个原理,在使用seata
的时候事务顺序就得考虑像TCC
这种事务特性
了,切记不要先去增加金额等等。
它对业务的侵入性为零
,你业务该怎么写就怎么写,就当只有这一个数据库的写就行了,只需要在配置中设置事务分组
,和使用@GlobalTransaction
,由Seata
进行代理数据源@EnableAutoDataSourceProxy
,如果光看业务层代码,你甚至不知道这是分布式事务。