Seata 笔记
分布式事务理论基础
CAP 定理
- Consistency 一致性:用户访问分布式系统中的任意节点得到的结果都是一致的
- Availability 可用性:用户和访问任意健康节点都必须得到响应而不是超时拒绝
- Partition tolernance 分区容错性:出现独立分区时整个系统依然要对外提供服务
- Partition 分区:因为网路故障或其他愿意导致分布式系统中的部分节点于其他节点失去连接,形成独立分区,独立分区内部节点可以同步数据而分区之间不能同步
分布式系统不可能同时满足这三个指标,最多满足两个
BASE 理论
BASE 理论时戳CAP的一种解决思路,其包括三个思想:
- Basically Available 基本可用:分布式系统出现故障时,允许损失部分可用性,即保证核心可用
- Soft State 软状态:允许系统在一定时间内出现中间状态,即临时的不一致性
- Eventually Consistent 最终一致性:在软状态结束后,系统最终保持数据一致
基于 CAP 定理额 BASE 理论的几种模式:
- AP 模式:各子事务分别执行和提交,允许出现结果不一致性,然后采用弥补措施恢复数据即可,实现最终一致
- CP 模式:各个字数五执行后相互等待,同时提交,同时回滚,实现强一致性,但是事务等待过程中处于弱可用状态
Seata 架构
Seata 事务管理中的三个重要角色
- TC(Transaction Corrdinator) 事务协调者:维护全局和分支事务状态,协调全局事务提交或回滚
- TM(Transaction Manager) 事务管理器:定义全局事务的范围,开始全局事务,提交或ui滚全局事务
- RM(Resource Manager) 资源管理器:管理分支事务处理的资源,与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚
Seata 提供的分布式事务解决方案:
- XA 模式:强一致性分阶段事务模式,牺牲了一定可用性,对业务无侵入
- AT 模式:最终一致分阶段事务模式,对业务无侵入,Seata 的默认模式
- TCC 模式:最终一致的分阶段事务模式,对业务代码有侵入
- SAGA 模式:长事务模式,对业务有侵入
XA 模式
XA 规范是 X/Open 组织定义的分布式事务处理(DTP, Distributed Transaction Processing)标准,描述了全局TM与局部RM之间的接口,几乎所有的主流数据库都对 XA 规范提供了支持,其分为两个阶段
- TM 通知 RM 执行各自的业务,RM 准备好后不提交,通知 TM 以就绪,若失败则发送失败通知给 TM
- TM 收到所有 RM 的就绪通知后通知各个 RM 提交事务,若第一阶段收到了失败通知则通知所有的 RM 进行回滚
XA 模式优点:
- 实现了分布式事务的强一致性,满足 ACID 原则
- 常用数据库都支持 XA 模式,实现简单,对业务代码没有侵入
XA 模式缺点:
- 第一阶段锁定数据库资源,等待第二阶段结束才释放,所以性能较差
- 依赖数据库本身的事务,若数据库不支持则无法使用
XA 模式使用:
- 配置文件,对数据源进行代理,之后微服务的sql语句执行都会被数据源的代理对象拦截下来,RM 内部执行相应操作:
seata:
data-source-proxy-mode: XA
- 全局事务入口方法处加上
@GlobalTransactional
注解
AT 模式
AT 模式和 XA 模式同样为分阶段提交的事务模型,其解决了 XA 模式中资源锁定时间过长的问题,其两个阶段为:
- TM 通知 RM 执行各自的业务,RM 执行业务并直接提交事务,将事务的更新信息存入 undo log(数据快照) 中,并向 TM 发送成功和失败通知
- 若所有 RM 都成功,则删除快照,否则根据快照进行回滚来恢复数据
AT 模式与 XA 模式的区别:
- XA 模式一阶段不提交事务,锁定资源, AT 模式一阶段提交事务,不锁定资源
- XA 模式依赖数据库事务实现回滚,AT 模式利用数据快照进行回滚
- XA 模式实现的为强一致性,而 AT 模式为最终一致性
AT 模式的脏写问题
为了解决 AT 模式的脏写问题,Seata 引入了全局锁来实现事务的写隔离,其由 TC 记录当前正在操作某行数据的事务,该事务持有全局锁,具备执行权
在全局锁实现中,TC 会创建一张表,存有事务 id,事务操作的表和表中的某个 id(对应事务操作的该表中的数据行),有点类似 MVCC
AT 模式中,数据快照保存由两份,一份为事务跟新数据前的快照(before-image)和事务提交前的快照(after-image),事务回滚时两份快照不一致时说明存在非 seata 管理的事务对数据进行了操作,说明数据无法恢复
AT 模式优点:
- 一阶段直接提交数据库事务,释放数据库资源,性能相比 XA 模式更好
- 利用全局锁实现隔离性
- 框架自动完成事务的回滚和提交,对业务代码无侵入
AT 模式缺点:
- 实现的是最终一致性,两阶段之间处于软状态,数据不一致
- 框架的快照生成和处理会影响数据库性能
AT 模式的使用
- 在微服务关联的数据库中创建相应的快照 undo_log 表和全局锁 lock_table 表
- 配置文件:
seata:
data-source-proxy-mode: AT
- 全局事务入口方法处加上
@GlobalTransactional
注解
TCC 模式
TCC 模式同 AT 模式一样,每个阶段都是独立事务,但是 TCC 模式需要手动编码来实现数据恢复,需要实现三个方法:
- Try:资源的检测和预留
- Confirm:完成资源操作业务,Try成功后调用,失败会重试
- Cancel:预留资源释放,可以视作 Try 的反向操作,失败会重试
TCC 模式优点:
- 一阶段直接提交事务,释放数据库资源,性能好
- 相比 AT 模式,无需生成快照,也无需使用全局锁,性能更好
- 不依赖数据库事务,可以适用在非事务型数据库
TCC 模式缺点:
- 需要手动实现 Try,Confirm,Cancel 三个方法,对业务代码由侵入
- 需要考虑 Confirm 和 Cancel 的失败情况,需要做好幂等处理
TCC 空回滚和业务悬挂
当某分支事务的 try 阶段阻塞时,可能导致全局事务超时而触发二阶段的 cancel 操作。在未执行 try 操作时先执行了 cancel 操作,这是 cancel 不能做回滚,即空回滚
对于已经空回滚的业务,如果以后执行 try,就永远不可能 confirm 或 cancel,即业务悬挂,应当组织执行空回滚后的 try 操作,避免悬挂
解决:在数据库的表中添加一个额外的字段来记录事务状态,是出于 try,confirm 和 cancel 中的那个阶段
- 判断空回滚:在 cancel 中,查询 try 的操作是否成功,如果查询不到数据则进行空回滚
- 避免业务悬挂:在 try 中,查询 cancel 是否释放了资源,若查询到 cancel 已经执行,则拒绝执行 try 业务
TCC 模式的使用
编写 TCC 接口并编写实现类
@LocalTCC
public interface TCCService {
/**
* try 方法
* @TwoPhaseBusinessAction 注解中的name属性与方法名一致,commitMethod 属性 rollbaclMethod 属性用于指定 confirm 和 cancel 方法
* @BusinessACtionContextParameter 注解标记的属性会放在上下文中,confirm 和 cancel 方法都能通过上下文拿到该属性信息
**/
@TwoPhaseBusinessAction(name = "prepare", commitMethod = "confirm", rollbaclMethod = "cancel")
void prepare(@BusinessActionContextParameter(ParamName = "param") String param);
/**
* confirm 方法
**/
boolean confirm(BusinessActionContext context);
/**
* confirm 方法
**/
boolean cancel(BusinessActionContext context);
}
Saga 模式
Saga 模式是 Seata 提供的长事务解决方案,分为两个阶段:
- RM 直接提交本地事务
- 若所有的本地事务都成功则什么事都不做,若存在事务失败则执行手动编写的补偿业务来回滚
Saga 模式优点:
- 可以实现基于事件驱动的异步调用,吞吐量高
- 一阶段直接提交事务,释放数据库资源,性能好
- 不用向 TCC 模式一样编写三个阶段的业务代码,实现相对简单
Saga 模式的缺点
- 软状态持续事件不确定,时效性差
- 没有事务隔离机制,存在脏写现象