分布式事物
一、2PC(Two-Phase Commit,两阶段提交)
✦ 背景动机:
最基础的分布式事务协议,由数据库起家(如 XA),核心在于协调者统一控制多个资源的提交与回滚。
✦ 操作流程:
-
阶段一:Prepare(准备阶段)
-
协调者向各参与者发送“准备提交事务”的请求。
-
每个参与者执行事务操作,写入undo log(用于回滚),然后锁定相关资源(如数据库锁)。
-
成功后回复“YES”,否则“NO”。
-
-
阶段二:Commit(提交阶段)
-
如果协调者收到所有“YES”,发送“提交”指令;否则发送“回滚”指令。
-
各参与者收到后执行提交或回滚操作。
-
✦ 优点:
-
实现简单;
-
一致性强(满足原子性:要么都提交,要么都回滚)。
✦ 缺点及问题:
-
阻塞问题:参与者在Prepare后必须等待协调者,资源锁未释放,导致阻塞。
-
单点故障问题:协调者如果崩溃,参与者无法得知提交或回滚结果,进入不确定状态。
-
无自动恢复机制:依赖协调者人工或脚本介入恢复。
二、3PC(Three-Phase Commit,三阶段提交)
✦ 背景动机:
为了解决2PC的阻塞和不确定性问题,3PC 在 2PC 的基础上引入了:
-
中间状态(Pre-Commit);
-
超时机制,避免永久阻塞;
-
所有节点都可以基于状态做出决策。
✦ 操作流程:
-
Can Commit 阶段(询问提交)
-
协调者发送“是否可以提交”;
-
参与者判断能否执行,若可以则返回“Yes”;
-
此阶段不做任何实际操作。
-
-
Pre-Commit 阶段(预提交)
-
如果都返回“Yes”,协调者发送“预提交”命令;
-
参与者执行事务逻辑,但不提交,进入“可提交”状态,并记录日志;
-
此时可以安全中断并重试。
-
-
Do Commit 阶段(正式提交)
-
协调者发送最终“提交”指令;
-
若超时未收到协调者指令,参与者也可自主提交(因为已进入可提交状态)。
-
✦ 优点:
-
避免阻塞:参与者等待超时可以自主提交或回滚;
-
引入中间状态更易于恢复;
-
状态明确:参与者通过自身状态判断可否提交。
✦ 缺点:
-
实现复杂度更高;
-
仍存在分布式网络不可靠带来的边缘问题(如脑裂);
-
较少系统真正采用,更多用于教学和理论研究。
三、TCC(Try-Confirm-Cancel)
✦ 背景动机:
2PC/3PC适合数据库层面事务,但业务更复杂时,需要应用层控制事务。TCC就是基于这种“资源预留-确认-取消”的业务建模思想。
✦ 操作流程:
-
Try:资源预留
-
尝试执行事务,检查业务约束,预留资源(如冻结库存/余额),但不做实际变更。
-
-
Confirm:确认提交
-
如果 Try 阶段所有参与者都成功,调用 Confirm 执行实际操作(扣库存/转账)。
-
-
Cancel:取消回滚
-
如果 Try 失败或超时未确认,执行 Cancel 释放资源。
-
✦ 示例:
电商下单 → 减库存、扣余额、创建订单:
-
Try:冻结库存、冻结金额;
-
Confirm:真正扣除、生成订单;
-
Cancel:释放冻结。
✦ 优点:
-
高灵活性、强一致性;
-
明确的业务隔离逻辑;
-
每个阶段幂等,便于容错处理。
✦ 缺点:
-
实现成本高:需要为每个接口编写 Try、Confirm、Cancel 三个接口;
-
资源浪费问题:预留资源可能一直未释放(如用户未支付);
-
强依赖幂等、空补偿控制(如 Cancel 要能容忍资源未冻结的情况)。
四、Saga(编排型事务,补偿事务)
✦ 背景动机:
当业务流程长、参与节点多(如旅游、酒店、机票等),全局锁资源成本极高。Saga 采用 补偿思路,每个子事务成功后就执行下一个,如果某个子事务失败,就反向执行补偿。
✦ 操作流程:
-
正向执行:T1 → T2 → T3 → T4
-
若 T3 执行失败,则依次执行:C2 → C1(即对 T2、T1 的补偿操作)
每个 Tn 和 Cn 需要成对实现。
✦ 示例:
下订单:
-
T1:扣库存;
-
T2:扣余额;
-
T3:发短信通知 → 失败;
-
C2:退款;
-
C1:还原库存。
✦ 优点:
-
非阻塞,异步执行;
-
不需要锁全局资源;
-
比 TCC 更灵活,适合长流程。
✦ 缺点:
-
只能补偿,不能“真正回滚”,不是强一致;
-
每个步骤必须实现 Cn 补偿逻辑;
-
补偿可能失败(如库存补不回来);
-
幂等、空补偿等问题依旧需要处理。
五、基于消息队列的事务消息(最终一致性)
✦ 背景动机:
适用于系统解耦、异步化场景,追求“最终一致性而非强一致性”,比如订单、发券、积分发放等。
✦ 操作流程(以 RocketMQ 为例):
-
生产者先发送“半消息”至 MQ;
-
本地事务执行(如写订单数据库);
-
成功后提交消息到 MQ,消费者才能收到;
-
若执行失败,回滚本地事务,并让 MQ 丢弃该半消息;
-
若网络异常,MQ 会回查本地事务状态。
✦ 优点:
-
异步高性能;
-
不阻塞主流程;
-
适合最终一致的场景。
✦ 缺点:
-
需要本地事务和消息发送保持一致性,对实现要求高;
-
需要处理 MQ 消息幂等、顺序性、重复消费;
-
不能保证强一致,只保证“最终一致性”。
总结对比(深入维度):
特性 | 2PC | 3PC | TCC | Saga | 消息队列事务 |
---|---|---|---|---|---|
一致性 | 强一致 | 强一致 | 强一致 | 最终一致 | 最终一致 |
阻塞 | 是 | 否 | 否 | 否 | 否 |
容错能力 | 差 | 一般 | 好 | 好 | 好 |
实现复杂度 | 中 | 高 | 高 | 高 | 中 |
编程复杂度 | 低 | 高 | 高 | 高 | 中 |
恢复机制 | 无 | 有 | 有 | 有 | 有 |
适用场景 | 金融、支付 | 理论性 | 资源控制型业务 | 长流程补偿型 | 解耦+异步业务 |