Seata实战
Seata 全局事务执行流程详解
在分布式系统中,跨服务、跨数据库的事务一致性一直是个难题。Seata 作为一个开源的分布式事务解决方案,通过 全局事务 的设计,实现了对业务侵入性较低的分布式事务控制。本文将从整体流程入手,剖析 Seata 的全局事务是如何开启、传播、注册、提交和回滚的,并重点介绍 AT 模式下的实现机制。
1. Seata 架构角色回顾
Seata 的分布式事务由三类核心角色协同完成:
- TM(Transaction Manager,事务管理器):事务的发起方,负责开启、提交或回滚全局事务。
- TC(Transaction Coordinator,事务协调器):事务的“大脑”,负责维护全局事务的状态,协调各分支事务的提交或回滚。
- RM(Resource Manager,资源管理器):资源的控制者,负责分支事务的注册,并执行资源的提交或回滚。
2. 全局事务执行流程
2.1 全局事务的开启
- TM 向 TC 申请开启一个全局事务。
- TC 成功创建全局事务并返回一个 唯一的全局事务 ID(XID)。
- 这个 XID 会通过 上下文传播(通常使用 AOP 实现),贯穿后续服务调用链路,以确保所有分支事务都能归属于同一个全局事务。
示例:在业务代码中通过 @GlobalTransactional
注解标记事务的开始。
2.2 分支事务的注册
- 每个服务执行本地事务时,由 RM 向 TC 注册分支事务。
- RM 报告当前资源的准备状态,并将分支事务与 XID 进行绑定。
- 分支事务实际上是 分布式事务中的独立本地事务。
2.3 全局提交或回滚的发起
-
当业务逻辑完成后,TM 根据执行结果向 TC 发起请求:
- 若业务成功 → 全局提交;
- 若业务异常 → 全局回滚。
-
这一步标志着事务 一阶段的结束。
2.4 提交或回滚的决定
- TC 汇总所有分支事务的状态。
- 根据状态决定整个分布式事务是 提交 还是 回滚。
2.5 提交或回滚的执行
- TC 将最终的决定通知所有 RM。
- 各 RM 根据通知执行资源的提交或回滚,完成事务 二阶段 的操作。
3. 四大模式的特殊实现
Seata一共分为四大模式:
- XA
- AT
- TCC
- SAGA
3.1 XA模式实现
原理
流程:
- 首先TM开启全局事务
- 全局入口调用微服务,然后被调用的分支事务注册到TC
- RM执行本地sql,锁住资源,但是不提交事务,而是向TC提交事务状态。
- TC根据每个事务状态,来决定统一回滚还是提交事务。
优点:
总结:
XA操作简单,但是它第一阶段需要锁定数据库资源,等待第二阶段才释放,如果第二阶段奔溃,可能出现阻塞问题,性能较差,以及高可用性较差,但是它是强一致性的,需要实现强一致性操作的可以使用。
代码实现
1、进行yml文件配置,将mode修改为XA
2、并在全局事务入口服务添加@GlobalTransactional
,表示全局事务的开始
3、整体流程
3.2 AT模式实现
原理
流程:
-
阶段一RM的工作:① 注册分支事务 ② **记录undo-log(数据快照)**③ 执行业务sql并提交 ④报告事务状态
-
阶段二,如果事务没问题,进行提交时RM的工作:删除undo-log即可
-
阶段二,如果事务出现异常,进行回滚时RM的工作:根据undo-log恢复数据到更新前
at模式牺牲了一致性,保证了可用性,不过,它保证的是最终一致性
优点:
XA和AT区别:
AT优点:
缺点:AT 模式为了保证隔离性,在一阶段提交业务数据后,会通过 全局锁 来防止其他事务修改相同的数据。
当
原因:当事务1释放事务锁时候,此时事务2进行数据更新,更新完释放锁,然后此时事务1发生了回滚,然后导致对应的数据更新被覆盖出现写操作异常,导致事务2的数据好像**“白忙活了”**
解决:在提交事务之前添加一个全局锁,但是性能可能比较低
总结:
AT操作复杂,但是全部都有seata底层完成了,它第一阶段不需要锁定数据库资源,但是需要记录数据更新前后的数快照保存到对应的undo log日志中,等待事务状态来决定删除 undo log 还是 回滚,这样保证了它是一个最终一致性的。
代码实现
1、进行yml文件配置,将mode修改为AT
2、并在全局事务入口服务添加@GlobalTransactional
,表示全局事务的开始
3、在部署seat的数据库中添加 lock_table 表,并在微服务关联的数据库导入undo_log表
4、整体流程
3.3 TCC模式实现
原理
流程:
- Try:尝试待执行的业务。订单系统将当前订单状态设置为支付中,库存系统校验当前剩余库存数量是否大于1,然后将可用库存数量设置为库存剩余数量-1,。
- Confirm:确认执行业务,如果Try阶段执行成功,接着执行Confirm 阶段,将订单状态修改为支付成功,库存剩余数量修改为可用库存数量。
- Cancel:取消待执行的业务,如果Try阶段执行失败,执行Cancel 阶段,将订单状态修改为支付失败,可用库存数量修改为库存剩余数量。
优点:
代码实现
1、进行yml文件配置,将mode修改为TCC
2、并在全局事务入口服务添加@GlobalTransactional
,表示全局事务的开始
3、然后独立编写try阶段代码
@LocalTCC // 若是本地接口,不使用 RPC
public interface AccountTccAction {
@TwoPhaseBusinessAction(
name = "AccountTccAction",
commitMethod = "commit",
rollbackMethod = "cancel")
boolean prepare(BusinessActionContext ctx,
@BusinessActionContextParameter(paramName="userId") String uid,
@BusinessActionContextParameter(paramName="amount") BigDecimal amt);
boolean commit(BusinessActionContext ctx);
boolean cancel(BusinessActionContext ctx);
}
@Service
public class BusinessService {
@Autowired AccountTccAction accountTcc;
@GlobalTransactional
public void doOrder(String buyerId, BigDecimal amt) {
boolean ok = accountTcc.prepare(null, buyerId, amt);
if (!ok) throw new RuntimeException("预扣失败");
// 其他服务 Try 阶段...
}
}
3.4 SAGA模式实现
原理
具体实现自行了解
4. 高可用
- 配置seta-demo:也就是集群分片
- 然后进行seata集群部署,并将该配置放到 nacos 中,可以进行动态更新切换对应的集群
5. 总结
Seata 的分布式事务执行过程可以概括为:
- TM 开启全局事务并生成 XID。
- RM 注册分支事务并绑定 XID。
- TM 发起全局提交或回滚请求。
- TC 决定并协调所有分支的最终执行。
- RM 根据指令完成资源的提交或回滚。