分布式事务方案横向对比与生产选型
市场上分布式事务方案众多:Seata 四模式、RocketMQ 事务消息、本地消息表、最大努力通知,还有 Hmily、TCC-Transaction 等 TCC 框架。本文把它们放在同一张对比表里,结合真实业务给出选型决策方法。
方案全景
按一致性强度分类
强一致类:
├─ XA 协议(数据库原生 / Seata XA)
└─ 2PC / 3PC 应用层实现
较强一致类:
└─ TCC(Try 预留资源,Confirm/Cancel 补偿)
最终一致类:
├─ Seata AT(自动镜像 + 全局锁)
├─ Seata SAGA / 各 SAGA 框架
├─ RocketMQ 事务消息
├─ 本地消息表
└─ 最大努力通知按侵入程度分类
低侵入:
├─ Seata AT(注解 + 自动 SQL)
├─ Seata XA(注解)
└─ RocketMQ 事务消息(事务监听器)
中侵入:
├─ Seata SAGA(状态机 JSON)
└─ 本地消息表(业务表 + 消息表 + 定时任务)
高侵入:
├─ TCC(每个接口三套逻辑)
└─ 手动 2PC(自行实现协调者)逐方案详解
Seata AT 模式
原理:代理数据源 → 前后镜像 → undo_log → 二阶段回滚
一致性:最终一致(带全局锁,无脏写)
侵入性:低(@GlobalTransactional)| 优点 | 缺点 |
|---|---|
| 业务代码几乎不变 | 全局锁降低高并发吞吐 |
| SQL 自动处理 | 复杂 SQL(多表 join)支持有限 |
| 生态成熟 | 需要 undo_log 表与全局锁表 |
Seata TCC 模式
原理:Try 预留 → Confirm 确认 / Cancel 补偿
一致性:较强
侵入性:高| 优点 | 缺点 |
|---|---|
| 不锁数据库资源 | 每个接口三套逻辑,成本高 |
| 高并发性能好 | 空回滚、悬挂、幂等需自行处理 |
| 适用资金场景 | 对业务建模要求高 |
Seata SAGA 模式
原理:步骤序列 + 反向补偿,状态机编排
一致性:最终一致
侵入性:中| 优点 | 缺点 |
|---|---|
| 适合长流程 | 中间状态对外可见 |
| 状态机可视化 | 状态机定义复杂,学习成本高 |
| 支持断点续跑 | 补偿设计要仔细 |
Seata XA 模式
原理:数据库 XA 协议,Seata 封装协调
一致性:强一致
侵入性:低| 优点 | 缺点 |
|---|---|
| 强一致,数据库原生保证 | 锁资源时间长,性能差 |
| 业务无感 | 依赖数据库 XA 支持 |
| 代码最简单 | 不适用高并发 |
RocketMQ 事务消息
原理:半消息 + 本地事务 + 回查
一致性:最终一致
侵入性:低(实现本地事务监听器)| 优点 | 缺点 |
|---|---|
| 异步解耦,性能高 | 只解决"业务 + 消息"两类一致性 |
| 与现有 MQ 体系融合 | 需要 MQ 高可用保障 |
| 回查保证可靠性 | 不适合多库强一致 |
本地消息表
原理:业务与消息同库同事务 + 定时任务投递
一致性:最终一致
侵入性:中| 优点 | 缺点 |
|---|---|
| 实现简单,无额外组件 | 消息表与业务耦合 |
| 可靠性高(同库事务) | 定时投递有延迟 |
| 与任何 MQ 兼容 | 需要补偿与去重机制 |
最大努力通知
原理:发起方尽力通知,接收方轮询查询兜底
一致性:最终一致
侵入性:低典型场景:
支付结果通知 → 商户回调
失败后多次重试(如 5 次)
仍失败 → 商户主动查询订单状态兜底| 优点 | 缺点 |
|---|---|
| 简单直接 | 通知不保证送达 |
| 双方解耦 | 依赖接收方查询兜底 |
| 适合外部系统对接 | 一致性较弱 |
横向对比总表
| 方案 | 一致性 | 侵入性 | 性能 | 组件依赖 | 典型场景 |
|---|---|---|---|---|---|
| Seata AT | 最终一致 | 低 | 中 | Seata + 数据库 | 跨库快速接入 |
| Seata TCC | 较强 | 高 | 高 | Seata | 资金、库存强管控 |
| Seata SAGA | 最终一致 | 中 | 高 | Seata | 长流程编排 |
| Seata XA | 强一致 | 低 | 低 | Seata + 数据库 XA | 强一致、低并发 |
| RocketMQ 事务消息 | 最终一致 | 低 | 高 | RocketMQ | 下单发消息 |
| 本地消息表 | 最终一致 | 中 | 中 | MQ + 定时任务 | 可靠消息投递 |
| 最大努力通知 | 最终一致 | 低 | 高 | 无 | 外部回调通知 |
选型决策树
第一步:问一致性强弱
业务必须强一致(任何时刻都不能看到中间状态)?
├─ 是,且并发低、数据源支持 XA → Seata XA
├─ 是,且并发高、能接受三接口成本 → TCC
└─ 否,最终一致即可 → 进入第二步第二步:问业务形态
业务形态是?
├─ 跨库写 + 简单 SQL → Seata AT
├─ 多步骤长流程 → Seata SAGA
├─ 业务 + 发消息 → RocketMQ 事务消息 / 本地消息表
├─ 异步通知外部 → 最大努力通知
└─ 混合 → 组合使用第三步:问团队与运维
├─ 团队能否维护额外组件(Seata 集群)?
│ ├─ 能 → Seata 系列
│ └─ 不能 → 消息方案(更轻)
├─ 已有 RocketMQ 基础设施?→ 优先事务消息
├─ 对监控 / 一致性审计有要求?→ Seata(控制台可视化)
└─ 异构语言(非 Java)多?→ 消息方案 / SAGA(语言无关性好)组合使用案例
电商下单全链路
下单链路拆解:
├─ 订单 + 库存(跨库强管控)→ Seata TCC
│ Try:冻结库存 → Confirm:扣减 → Cancel:释放
├─ 订单 + 账户(余额扣减)→ Seata AT(快速接入)
├─ 订单 + 积分 → RocketMQ 事务消息(异步,可延迟)
└─ 订单 + 短信通知 → 本地消息表(尽力投递)支付回调场景
支付平台 → 回调通知 → 商户
├─ 支付平台用最大努力通知(多次回调 + 签名验签)
├─ 商户幂等处理回调(订单状态机校验)
└─ 对账任务兜底(日终对账发现差异自动修复)混合原则
组合选型的三条原则:
├─ 核心链路强一致,非核心最终一致
├─ 同一链路尽量只用一个方案(降低复杂度)
└─ 所有方案都要配幂等 + 对账兜底常见误区
误区一:什么场景都用 Seata AT
高并发资金场景用 AT 会因全局锁产生瓶颈 → 用 TCC
误区二:TCC 一定能保证强一致
Try 与 Confirm 之间有窗口期,外部可能读到中间态
→ TCC 是"较强一致",不是强一致
误区三:事务消息能解决所有消息一致性问题
事务消息只保证"发送与本地事务一致"
→ 消费端幂等、消息丢失兜底仍要自己做
误区四:有了分布式事务就不需要幂等
分布式事务本身会重试(锁冲突、网络抖动)
→ 幂等是分布式系统的底线,缺一不可总结
选型的本质是用可接受的代价换取合适的一致性:要强一致且低并发选 XA,要高并发且能写三接口选 TCC,要快速接入跨库选 AT,要长流程编排选 SAGA,异步场景优先消息方案。没有"最好的分布式事务方案",只有"当前业务最合适"的组合。记住一条铁律:无论选哪个方案,幂等与对账兜底都不可省略。