分布式事务框架:SEATA
什么是分布式事务
本地事务 :
用数据库本身提供的事务特性来实现,也叫数据库事务。
分布式事务 :
事务的参与者位于不同的节点、不同的应用,操作不同的数据库,单个数据库事务无法控制参与者的操作同时成功or同时失败
因此有了分布式事务。
Seata简介
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。
Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
官方网站:https://seata.io/zh-cn/docs/overview/what-is-seata.html
各模式的优缺点
项目 | AT模式 | TCC模式 | XA模式 |
---|---|---|---|
描述 | 会代理Datasource进行数据库操作,2PC模式的改良版 | 不会代理应用的数据库操作 | X/Open组织定义了分布式事务接口,Oracle、mysql等厂商进行具体的实现 |
一致性 | 最终一致性 | 强一致性 | |
整合方法 | @GlobalTransactional + undo_log(事务回滚日志表) | @LocalTCC、@TwoPhaseBusinessAction、定义3个接口对应3个阶段 | @GlobalTransactional |
优点1 | 无侵入性,很少分布式事务相关代码 | 性能高,框架层面解决了空回滚、幂等性、防悬挂的问题 | 无侵入性,极少分布式事务相关代码 |
优点2 | 弥补了 XA 模式中资源锁定周期过长的缺点,增加了undo_log 机制,性能更好 | 应用自主程度高,事务参与者不局限于数据库,可延伸至其它组件如:Redis | 支持任何实现了 XA 协议的数据源 |
缺点1 | 只能回滚数据库这种资源 | 侵入性高,应用需要以 TCC 规范去编写业务逻辑 | 只能回滚数据库这种资源 |
缺点2 | 不适合用于单个SQL修改大量数据的场景 | 改造成本大,对于存量业务来说,需要将原本的业务逻辑一分为三 | 性能差 |
适用场景 | 适用于依靠关系型数据库的保存数据的业务场景 | 对性能有较高要求的业务场景 | 适用于基于 XA 协议设计且无法进行改造的业务场景 |
AT模式是如何弥补XA模式资源锁定周期过长这个缺点的?
AT模式不锁定资源,而是先生成执行前的数据快照,然后直接执行并提交;
然后记录执行后的数据快照;
一旦需要回滚了,便直接用旧的数据快照覆盖新的即可;
什么是空回滚、幂等性、防悬挂?
略
简单讲讲AT、tcc、XA 3种模式分别的原理?
参考:https://wu55555.blog.csdn.net/article/details/124510770
1.AT模式
AT模式中,假设有服务A,服务B,服务C
服务A,标记了@GlobalTransactional,因此服务A属于TM;
服务B、C,被服务A调用,因此是RM;
还有一个Seata-Server,负责全局事务的协调,是TC。
1.1 服务A向TC申请开启全局事务,获得一个全局事务ID(XID);
1.2 调用服务B并带上XID;
1.3 服务B向TC注册,并带上XID,好将服务B与服务A分到同一组;同时获得本地事务ID(BID)
1.4 服务B在提交前,服务B会:1. 申请全局行锁 2. 生成事务前数据快照(before image)
1.5 服务B提交后,还会生成事务后数据快照(after image)
1.6 然后,服务B提交事务执行结果
1.6.1 成功。根据before image,生成回滚SQL保存到undo_log里;
1.6.2 失败。根据after image,判断数据是否被脏读。有则报错,没有则事务回滚,并通知TC让其他本地事务回滚
1.7 服务C同理,按照1.3、1.4、1.5、1.6进行
1.8 服务A提交整体执行结果:(1)成功。TC通知服务A删除undo_log及其他事务管理数据;(2)失败:TM通知服务A所有本地事务回退
2.TCC模式
TCC模式中,有Try、Confirm、Cancel三个阶段。
假设现在有一个提交订单的场景。提交完订单后需要扣减库存。
2.1 Try阶段
- 创建订单,并标注为未提交
- 业务检查(是否有足够的库存扣减)
- 资源预留(冻结库存,冻结的库存其他业务不能使用)
2.2 Confirm阶段
- 将订单状态改为已提交
- 冻结的库存取消冻结,正式扣减
2.3 Cancel阶段
- 删除未提交的订单
- 取消冻结的库存
在锁使用的方面,整个实现TCC的过程,实际上是没有用到全局锁的,这是和AT模式另外一个大的区别。
TCC模式更多的是利用本地行锁或者乐观锁、状态区分的形式来实现资源隔离。
因为没有全局锁的限制,所以其速度飞快提升。因此呢TCC模式也就适用于对性能有较高的分布式事务场景。
2.4 建立TCC模式的重试机制
confirm或者cancel方法也出现报错时,为了保证事务的最终一致性,我们应当做好重试机制处理:
比如将请求发送MQ,然后再接收处理。
2.5 幂等性问题
如果扣减库存时多次重试,仍然能保证只扣了1次库存,这种就称为保证了幂等性。
换句话说,操作多次和操作一次的效果一样,就是所谓的幂等。
如何保证幂等性:
- 添加状态字段,判断是否执行过
2.6 悬挂问题(又叫空回滚)
所谓悬挂问题,就是二阶段模式中,cancel比try先执行。
拿上面的例子,cancel是解冻库存,try是将订单状态改为未提交。
2.6.1 因为网络问题,导致商品服务的try一直卡住,然后报错
2.6.2 TM通知库存服务回滚,执行了cancel方法,解冻了库存;
2.6.3 此时商品服务又好了,执行了try方法,将订单状态改为未提交;
2.6.4 然而事务已经被cancel过了,就不会再执行confirm,也就没有谁再来将资源状态从预处理更新为已处理了。
针对悬挂问题进行防悬挂处理,方案呢就是限制如果二阶段执行完成,一阶段就不能再执行。
当然这些处理呢,seata已经帮我们实现了,这也是使用现成的分布式事务框架的好处。省心!但是我们自己要知道这些问题和原理。
seata中的解决方案是增加一个事务记录表,在cancel阶段最后往事务记录表中插入一条记录(xid-status)标记cancel阶段已经执行过。
此时try阶段进入时发现已经执行过回滚操作,则放弃try阶段的执行