分布式事务常见解决方案总览
凌晨 3 点,你的报警平台突然炸了——订单服务说库存服务没扣库存,库存服务说订单服务没发请求,财务系统一脸懵逼:「钱扣了,货呢?」
这不是 bug,这是分布式事务的经典困境:跨服务的数据一致性。
为什么分布式事务是分布式系统最大的难题之一?因为它直接撞上了 CAP 理论 的天花板—— Consistency(一致性)、Availability(可用性)、Partition tolerance(分区容错性),三者只能选其二,而网络分区是必然发生的。
换句话说:在分布式系统中,要么接受数据不一致,要么接受系统不可用。分布式事务的种种方案,本质上都是在这两者之间寻找平衡点。
从强一致到最终一致:一条艰难的路
分布式事务解决方案可以分为两大阵营:
强一致性方案:不惜一切代价保证数据完全一致
最终一致性方案:允许短暂的不一致,但保证最终一致
| 方案 | 一致性级别 | 性能 | 开发成本 | 适用场景 |
|---|---|---|---|---|
| 2PC/3PC | 强一致 | 差 | 中 | 对数据一致性要求极高的场景 |
| Seata AT | 强一致 | 中 | 低 | 业务代码无侵入,支持单库多表 |
| Seata TCC | 最终一致 | 高 | 高 | 高性能,强一致性,业务可改写 |
| Saga | 最终一致 | 高 | 中 | 长事务,流程编排 |
| 可靠消息 | 最终一致 | 高 | 中 | 异步解耦,允许短暂不一致 |
| 最大努力通知 | 最终一致 | 高 | 低 | 通知类场景,允许失败重试 |
没有银弹,每种方案都是一致性、成本、性能的权衡。选错方案,轻则系统卡顿,重则数据错乱。
强一致性方案:2PC 与 3PC
2PC(Two-Phase Commit)
2PC 是最经典的分布式事务协议,由协调者(Coordinator)和参与者(Participant)组成:
一阶段(投票阶段):
- 协调者向所有参与者发送「准备好」请求
- 参与者执行事务,但不提交
- 参与者返回「同意」或「反对」
二阶段(提交阶段):
- 如果所有参与者都返回「同意」,协调者发送「提交」指令
- 如果任何一个参与者返回「反对」,协调者发送「回滚」指令
2PC 的致命缺陷:
- 同步阻塞:参与者收到「准备好」后,必须阻塞等待,直到收到提交或回滚
- 单点故障:协调者挂了,参与者就死等了
- 数据不一致:协调者发送「提交」后挂了,只有部分参与者收到提交,导致数据不一致
3PC(Three-Phase Commit)
3PC 是 2PC 的改良版,把提交分成三个阶段:
- CanCommit:协调者问参与者「你们能提交吗」
- PreCommit:协调者告诉参与者「准备提交」,超时自动中断
- DoCommit:真正提交
3PC 解决了同步阻塞和单点故障的部分问题(超时机制),但数据不一致问题依然存在。
强一致性方案的共同问题:性能太差。全局锁、多次网络通信、参与者必须等待——这套机制在互联网高并发场景下几乎不可用。
最终一致性方案:百花齐放
强一致性方案性能太差,所以最终一致性方案应运而生。
核心思想:放弃实时一致,接受短暂不一致,用补偿机制保证最终一致。
TCC(Try-Confirm-Cancel)
Seata TCC 模式 把每个分布式事务分成三步:
- Try:预留资源,但不提交
- Confirm:确认执行,使用预留的资源
- Cancel:取消执行,释放预留的资源
关键点:Try/Confirm/Cancel 都需要业务方自己实现。TCC 是业务层面的补偿,需要在代码里写好预留、确认、取消的逻辑。
Saga
Seata Saga 模式 适合长事务编排。把一个大事务拆成多个小事务,每个小事务都有对应的补偿操作。正向执行,出错就反向补偿。
TCC vs Saga:
- TCC 是「先锁定再执行」,资源在 Try 阶段就被预留了
- Saga 是「直接执行,出事再补偿」,不锁定资源
可靠消息
可靠消息最终一致性方案 的核心是消息队列。本地事务执行成功后,消息一定被投递到下游。
两种实现方式:
- 本地消息表:本地事务 + 消息表,用定时任务轮询投递
- RocketMQ 事务消息:半消息(Half Message)机制,反查本地事务状态
最大努力通知
最大努力通知方案 是「可靠消息」的镜像——可靠消息保证发送方,最大努力通知保证接收方。
典型场景:支付回调、订单状态同步。核心机制是重复通知 + 指数退避 + 衰减通知次数。
选型决策树:怎么快速选择?
需要强一致性?
├── 是 → 业务代码能改吗?
│ ├── 能 → TCC(高性能)或 AT(零侵入)
│ └── 不能 → AT 模式(如果有框架支持)
└── 否 → 是异步解耦还是长事务?
├── 异步解耦 → 可靠消息(MQ 事务消息)
└── 长事务 → Saga 编排更详细的选型分析:AT vs TCC vs SAGA 对比与选型
面试追问方向
CAP 理论在分布式事务中怎么体现?
- 强一致性方案选择了 C+P,意味着可能牺牲可用性
- 最终一致性方案选择了 A+P,在网络分区时保证可用,允许短暂不一致
2PC 的数据不一致问题怎么解决?
- 加协调者选举 Zab/Raft 协议
- 或者干脆不用 2PC,用最终一致性方案
如果让你设计一个分布式事务框架,核心模块有哪些?
- 事务协调器:管理全局事务状态
- 分支事务注册:让参与者加入全局事务
- 补偿/回滚机制:处理失败情况
- 隔离性保证:全局锁或资源预留
本地消息表和 RocketMQ 事务消息的区别?
- 本地消息表:业务自己实现,需要轮询任务
- RocketMQ 事务消息:MQ 原生支持,反查机制更可靠
没有银弹
分布式事务的难点不在于找到「完美方案」,而在于理解每种方案的权衡,根据业务场景做出合理选择。
是追求强一致还是最终一致?业务代码能改吗?性能要求有多高?能接受多长时间的窗口期?
这些问题没有标准答案,只有最适合当前业务的答案。
下次遇到分布式事务问题,别急着找框架,先问自己:这笔交易能承受多长时间的「不一致」?
