★ 分布式事务方案如何取舍?Seata AT 模式原理是什么?
结论先行:跨服务写多个库无法用单库事务,常见方案按“一致性强度 vs 吞吐/侵入”分档:XA(数据库层 2PC,强一致但阻塞)、Seata AT(无侵入自动补偿,业界主流)、TCC(业务补偿,高吞吐但侵入大)、Saga/本地消息表(最终一致,适合长流程)。Seata AT 的核心是“一阶段本地提交 + 二阶段反向补偿”,借助全局锁与 undo_log 实现近似强一致。
一、方案对比
| 方案 | 一致性 | 吞吐 | 业务侵入 | 适用 |
|---|---|---|---|---|
| XA 2PC | 强 | 低(资源锁到全局提交) | 低 | 同库技术栈、短事务 |
| Seata AT | 较强(最终一致+锁控制) | 中 | 低(注解即可) | 多服务多库常规事务 |
| TCC | 最终一致 | 高 | 高(Try/Confirm/Cancel 三方法) | 高并发、资源预留 |
| Saga | 最终一致 | 高 | 中(需补偿) | 长流程、无强一致 |
二、Seata 角色与 AT 模式流程
| 角色 | 职责 |
|---|---|
| TC(事务协调器) | 独立服务,管理全局事务状态 |
| TM(事务管理器) | 业务入口,开启/提交/回滚全局事务 |
| RM(资源管理器) | 各分支数据源,注册分支并执行本地事务 |
@GlobalTransactional // TM:开启全局事务(seata-all/spring-cloud-starter-alibaba-seata)
public void createOrder() {
orderService.insert(); // RM1:分支一
stockService.deduct(); // RM2:分支二
}
AT 两阶段:
- 一阶段:RM 解析业务 SQL,生成 undo_log(before/after 镜像),本地事务提交并注册分支,同时按主键加全局锁;
- 二阶段提交:TC 通知各 RM 异步清理 undo_log,释放全局锁;
- 二阶段回滚:RM 依据 undo_log 反向生成补偿 SQL(把数据恢复为 before 镜像),校验 after 未被他事务改过才回滚,防止脏写。
三、选型与取舍要点
- 每个业务库需建 undo_log 表;SQL 需能被解析(带主键的常规 CRUD),复杂 DDL/不走 SQL 的变更不支持;
- 全局锁影响并发:热点行写冲突会等待/失败,超高并发写场景谨慎;
- AT 也非完全无感:慢 SQL、长事务、大批量更新会放大锁与日志开销;
- 高并发写 + 可接受补偿设计 → 优先 TCC/Saga;简单跨库事务、并发可控 → AT 性价比最高。
常见追问 / 记忆点
- 追问:AT 与 XA 最大区别?答:XA 一阶段不提交、锁到全局结束;AT 一阶段就本地提交,靠 undo_log 与全局锁做补偿,锁窗口小、吞吐更高。
- 追问:什么时候不该上分布式事务框架?答:能通过接口幂等 + 对账/重试达到最终一致时,尽量别引全局事务,成本和风险更低。
- 记忆点:TC/TM/RM 三角色;一阶段提交 + undo_log 补偿 + 全局锁防脏写 = AT。