分布式事务
# 本地事务
满足数据库中的ACID
- 原子性:事务中的所有操作,要么全部成功,要么全部失败
- 一致性:要保证数据库内部完整性,满足约束
- 隔离性:对同一资源操作的事务不能同时发生
- 持久性:对数据库做的一切修改将永久保存
# 分布式事务
不是在单个服务或单个数据库架构下,产生的事务
# CAP定理
Consistency(一致性):用户访问分布式系统中的任意节点,得到的数据必须一致。
Availability(可用性):用户访问集群中任意健康节点,必须得到响应。
Partition tolerance (分区容错性):因为网络故障,分布式系统内部形成多个分区,也要对外提供服务。
矛盾
如果保证一致性,和可用性,那么当分布式系统中因为网络原因,有的节点无法通信,那么就会导致节点之间数据不同步,如果让数据不同步的节点不能访问,那么就不满足可用性,如果让他能访问,那么就不满足一致性。
# BASE理论
- Basically Available (基本可用):分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。
- **Soft State(软状态):**在一定时间内,允许出现中间状态,比如临时的不一致状态。
- Eventually Consistent(最终一致性):虽然无法保证强一致性,但是在软状态结束后,最终达到数据一致。
AP模式:各子事务分别执行和提交,允许出现结果不一致,然后采取弥补措施恢复数据即可,实现最终一致性。
CP模式:各个子事务执行后互相等待,同时提交,同时回滚,达成强一致性。
# Seata
Seata事务管理中有三个重要的角色:
TC (Transaction Coordinator) - **事务协调者:**维护全局和分支事务的状态,协调全局事务提交或回滚。
TM (Transaction Manager) - **事务管理器:**定义全局事务的范围、开始全局事务、提交或回滚全局事务。
RM (Resource Manager) - **资源管理器:**管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
Seata基于上述架构提供了四种不同的分布式事务解决方案:
- XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入
- TCC模式:最终一致的分阶段事务模式,有业务侵入
- AT模式:最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式
- SAGA模式:长事务模式,有业务侵入
# XA模式
两阶段提交
一阶段:
- 事务协调者通知每个事物参与者执行本地事务
- 本地事务执行完成后报告事务执行状态给事务协调者,此时事务不提交,继续持有数据库锁
二阶段:
- 事务协调者基于一阶段的报告来判断下一步操作
- 如果一阶段都成功,则通知所有事务参与者,提交事务
- 如果一阶段任意一个参与者失败,则通知所有事务参与者回滚事务
# AT模式
# AT与XA的区别
- XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。
- XA模式依赖数据库机制实现回滚;AT模式利用数据快照实现数据回滚。
- XA模式强一致;AT模式最终一致
# AT脏写问题
解决思路就是引入了全局锁的概念。在释放DB锁之前,先拿到全局锁。避免同一时刻有另外一个事务来操作当前数据。
# TCC模式
Try:资源的检测和预留;
Confirm:完成资源操作业务;要求 Try 成功 Confirm 一定要能成功。
Cancel:预留资源释放,可以理解为try的反向操作。
TCC的优点
- 一阶段完成直接提交事务,释放数据库资源,性能好
- 相比AT模型,无需生成快照,无需使用全局锁,性能最强
- 不依赖数据库事务,而是依赖补偿操作,可以用于非事务型数据库
TCC的缺点
- 有代码侵入,需要人为编写try、Confirm和Cancel接口,太麻烦
- 软状态,事务是最终一致
- 需要考虑Confirm和Cancel的失败情况,做好幂等处理
# 空回滚
当某分支事务的try阶段阻塞时,可能导致全局事务超时而触发二阶段的cancel操作。在未执行try操作时先执行了cancel操作,这时cancel不能做回滚,就是空回滚。
执行cancel操作时,应当判断try是否已经执行,如果尚未执行,则应该空回滚。
# 业务悬挂
对于已经空回滚的业务,之前被阻塞的try操作恢复,继续执行try,就永远不可能confirm或cancel ,事务一直处于中间状态,这就是业务悬挂。
执行try操作时,应当判断cancel是否已经执行过了,如果已经执行,应当阻止空回滚后的try操作,避免悬挂
# SAGA模式
分布式事务内有多个参与者,需要用户根据业务场景实现其正向操作和逆向回滚操作。
Saga也分为两个阶段:
- 一阶段:直接提交本地事务
- 二阶段:成功则什么都不做;失败则通过编写补偿业务来回滚