分布式事务方案怎么选?
更新时间:2026-09-18。问题驱动短答页,给出工程选型决策。
一句话回答
能不用分布式事务就不用:优先通过业务拆分、本地事务 + 消息驱动的最终一致来解决。确实需要跨服务/跨库原子性时,按「一致性要求 × 业务可改造程度」在 Seata AT(无侵入 2PC)、TCC(业务三阶段)、本地消息表/事务消息(可靠最终一致)、Saga(长流程补偿) 之间选;底层理论边界是 CAP/BASE。
决策顺序
bash
能否通过业务重构把跨库操作收回单库/单服务?
能 -> 本地事务,结束
不能 ↓
是否允许短时间不一致、只要最终一致?
是 -> 本地消息表 / 事务消息(最常用、最稳)
否 ↓
资源是否都支持长时间锁定且并发不高?
是 -> Seata AT(2PC,几乎无业务侵入,但要 undo_log、全局锁)
否 ↓
接口能否改造成 Try/Confirm/Cancel 且能幂等/空回滚/防悬挂?
能 -> TCC(性能好、一致性强,侵入最大)
是否是跨多步、长耗时业务流程(下单→库存→物流→退款)?
是 -> Saga(每步配补偿动作,最终一致)方案对比
| 方案 | 一致性 | 业务侵入 | 性能/可用性 | 典型场景 |
|---|---|---|---|---|
| 2PC/XA、Seata AT | 较强(AT 默认读已提交级最终) | 低(AT 自动生成回滚 SQL) | 有全局锁、RPC 协调开销 | 传统单体拆库、同构关系库 |
| TCC | 强(业务层面预留) | 高(写三个接口) | 高、不长期锁资源 | 资金、库存冻结 |
| 本地消息表/事务消息 | 最终一致 | 中 | 高、解耦 | 订单→积分→通知等绝大多数异步链路 |
| Saga | 最终一致 | 中(写补偿) | 高,适合长流程 | 跨多系统、可补偿的业务编排 |
| 纯补偿/对账 | 最终一致 | 低~中 | 高 | 可容忍延迟、靠对账兜底 |
关键工程要求
无论哪种最终一致方案,参与方都必须做到:
- 幂等:同一消息/补偿重复执行结果一致(唯一键、去重表、状态机只允许合法流转)。
- 空回滚/防悬挂(TCC):没收到 Try 也要能处理 Cancel;Cancel 后迟到的 Try 不能再执行。
- 可重试 + 死信告警:消费失败指数退避,进死信队列人工介入。
- 对账兜底:任何自动方案都可能有边角不一致,定时对账是最后防线。
为什么默认推荐本地消息表
把「业务变更」和「待发消息」放在同一个本地事务里写入业务表 + 消息表,由后台任务把消息投递到 MQ(投递可重试、可去重),下游消费成功后标记完成。它不长期锁资源、不依赖所有参与方在线,吞吐和可用性最好,代价是秒级延迟,而这正是大多数互联网业务能接受的。
相关与延伸
一致性理论基础(CAP/BASE)、服务熔断隔离可结合微服务系列阅读;接口层幂等见 接口幂等设计:token/唯一键/状态机、消息不重复消费的幂等做法也在其中;数据侧 binlog 同步常用作最终一致手段,见 CDC 数据同步:Canal/Debezium,强一致方案落地见 Seata AT/TCC 与本地消息表。
总结
先尝试用业务聚合和本地事务消灭跨库一致性;消灭不了且能接受秒级延迟,就用本地消息表/事务消息做可靠最终一致(最通用);需要强预留的资金库存用 TCC;同构关系库、想要低侵入可用 Seata AT(接受全局锁与 undo_log);长流程用 Saga 配补偿;所有最终一致方案都要做幂等、重试、死信与对账兜底。