分布式事务Seata-核心问题
Seata三大组件的协作流程
-
TM(事务管理器)发起全局事务
- 当业务方法被
@GlobalTransactional
标记时,TM向TC申请开启全局事务 - TC生成全局唯一XID并返回给TM
- 当业务方法被
-
XID在调用链中传播
- XID会通过微服务调用(如HTTP头、RPC上下文)传递到其他服务
-
RM(资源管理器)执行分支事务
- RM接收到XID后,向TC注册分支事务(绑定到该XID)
- RM执行本地事务,同时记录数据快照(
undo_log
)用于回滚
-
全局事务决议阶段
- TM(而非TC)根据业务逻辑决定提交/回滚,并通知TC
- TC收到决议后,调度所有关联RM执行最终操作(提交或回滚)
注意:TM才是决策者,TC只负责协调执行,不会主动通知TM做决定。
完整流程:TM启事务→TC发XID→RM干活留底→TM定结果→TC督执行
本地事务和分支事务的关联
- 本地事务
指单个微服务内通过数据库自身 ACID 特性实现的事务操作,例如单个数据库的增删改查操作。
- 分支事务
是全局事务的组成部分,对应单个微服务中的本地事务。每个分支事务独立执行并注册到 Seata 事务协调器(TC)中,由资源管理器(RM)管理其提交或回滚。
分支事务=本地事务+Seata协调逻辑(注册、锁、日志)
分支事务中如何保证数据一致性
分支事务通过2PC协议、本地ACID、Undo Log和隔离控制(读未提交)协同工作
两阶段提交的核心逻辑
-
第一阶段(Prepare Phase)
- 执行本地事务:每个分支事务(RM)执行本地SQL操作(如订单创建、库存扣减),但不提交事务。
- 生成回滚日志:记录数据修改前的快照(Undo Log),用于可能的回滚操作。
- 注册分支事务:RM向TC注册分支事务并关联全局事务ID(XID),此时事务状态为“未完成”。
-
第二阶段(Commit/Rollback Phase)
- TC决策:TC根据所有分支事务的执行状态(成功/失败)决定全局提交或回滚。
- 全局提交:通知所有RM删除回滚日志并提交本地事务。
- 全局回滚:通知RM根据回滚日志恢复数据,并终止本地事务
- TC决策:TC根据所有分支事务的执行状态(成功/失败)决定全局提交或回滚。
第一阶段预执行,第二阶段由TC统一决策
- “先做但不提交” = 第一阶段(Prepare Phase)的本地事务执行与日志记录。
- “TC通知提交/回滚” = 第二阶段(Commit/Rollback Phase)的全局协调
TC如何收集分支事务的状态
Seata的TC(事务协调器)通过以下机制收集分支事务状态:RM(资源管理器)在一阶段执行本地事务后主动上报状态(成功/失败)至TC,TC将状态持久化存储并监控超时;若分支未及时上报,TC会主动查询或触发超时回滚,最终基于全局状态决策提交或回滚。
Seata四种分布式事务模式
Seata提供四种分布式事务模式,分别针对不同业务场景设计,其核心原理与实现机制如下:
一、AT模式(Automatic Transaction)
- 原理:基于二阶段提交的增强版
- 一阶段:拦截业务SQL,生成前后镜像数据(Undo Log),执行本地事务但不提交。
- 二阶段:TC根据分支事务状态驱动全局提交(删除Undo Log)或回滚(通过镜像数据还原)。
- 特点:无侵入、高性能,依赖数据库本地事务能力。
二、TCC模式(Try-Confirm-Cancel)
- 原理:通过人工编码实现三阶段
- Try:预留资源(如冻结库存)。
- Confirm/Cancel:TC协调确认提交(解冻资源)或取消(释放资源)。
- 特点:需业务方实现补偿逻辑,适用于高并发场景。
三、Saga模式
- 原理:长事务拆分+逆向补偿
- 每个子事务提交后立即生效,失败时触发已提交事务的逆向操作。
- 通过状态机或注解定义事务链。
- 特点:最终一致性,适合跨服务长流程业务。
四、XA模式
- 原理:基于数据库原生XA协议
- 一阶段:RM执行事务并锁定资源,等待TC指令。
- 二阶段:TC通知所有RM提交或回滚。
- 特点:强一致性,但性能较低,依赖数据库支持。
模式对比
模式 | 一致性级别 | 侵入性 | 性能 | 适用场景 |
---|---|---|---|---|
AT | 最终一致 | 无 | 高 | 常规分布式事务 |
TCC | 最终一致 | 高 | 中高 | 高并发秒杀 |
Saga | 最终一致 | 中 | 高 | 长流程业务 |
XA | 强一致 | 无 | 低 | 传统金融系统 |
TCC模式在业务中如何实现?
核心阶段实现逻辑
-
Try阶段(资源预留)
- 业务检查:验证业务规则(如库存是否充足、账户余额是否足够)
- 资源预留:通过业务字段锁定资源(如冻结库存、预扣余额)
- 数据记录:生成中间状态数据(如预订单、冻结记录)
-
Confirm阶段(最终提交)
- 资源消费:将预留资源转为实际消费(如扣减真实库存)
- 状态更新:标记业务为完成状态(如订单状态改为"已支付")
- 幂等设计:需支持重复调用(如通过事务ID判断是否已处理)
-
Cancel阶段(资源释放)
- 反向操作:释放Try阶段预留的资源(如解冻库存、返还余额)
- 异常处理:需处理空回滚(Try未执行时的Cancel)和业务悬挂(Cancel晚于Try到达)
典型业务场景实现(电商下单)
服务 | Try阶段 | Confirm阶段 | Cancel阶段 |
---|---|---|---|
订单服务 | 创建状态为"预创建"的订单 | 更新订单为"已完成" | 取消订单并删除记录 |
库存服务 | 冻结对应商品库存(如锁定100件) | 扣减实际库存(100件) | 解冻库存(释放100件) |
支付服务 | 预扣用户账户余额(如冻结500元) | 实际扣款(500元) | 返还冻结金额(500元 |
如何确保Confirm和Cancel阶段的幂等性?
- 事务状态标记:通过全局唯一事务ID(XID)记录事务状态,执行前检查日志状态避免重复处理
- 业务设计约束:
- Confirm阶段仅依赖Try预留资源执行,不进行业务检查
- Cancel阶段需判断Try是否执行,避免空回滚
- 技术手段:
- 使用
UPDATE ... WHERE
等幂等SQL语句 - 框架层(如Seata)内置重试补偿机制
- 使用
- 异常处理:针对网络超时等问题,通过异步重试和事务日志恢复保证最终一致性
Seata框架如何内置重试补偿机制?
-
事务状态追踪与日志持久化
- 全局事务(XID)和分支事务状态持久化到事务日志表,作为重试依据
- 一阶段记录Before Image和After Image形成Undo Log,用于补偿时数据还原
-
自动重试策略
- 二阶段Confirm/Cancel失败时,基于事务日志触发异步重试,采用指数退避算法控制频率
- 默认重试次数可配置(如
maxCommitRetryTimeout=120000ms
)
-
补偿执行逻辑
- TCC模式:通过Try阶段预留的资源状态决定Confirm/Cancel执行路径
- AT模式:依赖Undo Log反向生成补偿SQL实现数据回滚
-
异常处理保障
- 锁冲突或超时异常自动触发重试
- SAGA模式通过逆向服务调用实现长事务补偿