两阶段提交协议(2PC):分布式事务的经典解决方案
在分布式系统中,确保跨多个节点的事务原子性(要么全成功,要么全失败)是核心挑战。两阶段提交协议(Two-phase Commit,2PC)是实现分布式事务的经典方案,通过 “准备” 与 “提交” 两个阶段协调所有参与者,保证数据一致性。
核心角色与目标
1. 角色划分
- 协调者(Coordinator):全局事务的管理者,负责发起事务、收集参与者反馈、最终决定提交或回滚。
- 参与者(Participants):分布式事务的执行者(如数据库节点、服务实例),负责执行本地事务,并响应协调者的指令。
2. 核心目标
保证跨节点事务的 ACID 特性,尤其是原子性(Atomicity):所有参与者要么都提交事务,要么都回滚,避免出现部分节点成功、部分节点失败的不一致状态。
执行流程
两阶段提交协议通过 “准备阶段” 和 “提交阶段” 分步骤完成分布式事务,具体流程如下:
阶段一:准备阶段(Vote Phase)
协调者向所有参与者发起 “准备提交” 请求,参与者执行本地事务但不提交,反馈执行结果。
- 协调者动作:
- 向所有参与者发送
PREPARE
消息,询问是否可以提交事务。 - 等待所有参与者的响应(同意或拒绝)。
- 向所有参与者发送
- 参与者动作:
- 收到
PREPARE
后,执行本地事务(如数据库INSERT
/UPDATE
),但不提交(保持事务处于未提交状态)。 - 记录事务日志(确保崩溃后可恢复)。
- 若本地执行成功,返回
YES
投票(同意提交);若失败,返回NO
投票(拒绝提交)。
- 收到
阶段二:提交阶段(Commit Phase)
协调者根据所有参与者的投票结果,决定事务最终 “提交” 或 “回滚”,并通知所有参与者执行相应操作。
- 情况一:所有参与者返回
YES
- 协调者发送
COMMIT
消息给所有参与者。 - 参与者收到
COMMIT
后,提交本地事务,释放资源,并返回ACK
确认。 - 协调者收到所有
ACK
后,标记事务成功结束。
- 协调者发送
- 情况二:至少有一个参与者返回
NO
- 协调者发送
ROLLBACK
消息给所有参与者。 - 参与者收到
ROLLBACK
后,回滚本地事务,释放资源,并返回ACK
确认。 - 协调者收到所有
ACK
后,标记事务失败结束。
- 协调者发送
关键机制:日志与持久化
为应对节点崩溃或网络中断,两阶段提交依赖 事务日志的持久化:
- 协调者和参与者在执行每个步骤前,必须将操作记录到本地日志(如数据库的 redo/undo 日志),确保崩溃后可通过日志恢复状态。
- 例如:参与者在返回
YES
前,需将 “已执行本地事务但未提交” 的状态写入日志,避免崩溃后丢失操作记录。
存在的问题与局限性
尽管 2PC 是分布式事务的基础方案,但仍存在以下问题:
1. 协调者单点故障风险
- 若协调者在 “提交阶段” 崩溃(如已发送
COMMIT
给部分参与者,未发送给其他参与者),未收到消息的参与者会一直阻塞(等待协调者指令),导致资源长期锁定。 - 缓解方案:
- 协调者设置备用节点,通过日志同步状态,故障时备用节点接替工作;
- 为事务设置超时时间,超时后参与者自主回滚(可能导致数据不一致,需谨慎使用)。
2. 阻塞问题(性能瓶颈)
- 准备阶段中,若某个参与者崩溃或网络中断,协调者会一直等待其响应,导致整个事务阻塞;
- 提交阶段中,参与者需等待协调者的
COMMIT
/ROLLBACK
指令,期间会锁定资源(如数据库行锁),降低系统并发度。
3. 数据不一致风险
- 若协调者发送
COMMIT
后崩溃,部分参与者成功提交,部分未收到消息的参与者会在超时后回滚,导致数据不一致; - 例如:银行转账中,A 账户已扣款(提交),B 账户未收到款项(回滚),出现资金丢失。
4. 不适合高并发场景
- 两阶段提交涉及多轮网络通信(协调者与所有参与者的交互),且参与者需长期锁定资源,性能较低,不适合高并发业务(如秒杀、高频交易)。
改进方案:三阶段提交(3PC)
为解决 2PC 的阻塞问题,三阶段提交(3PC)在其基础上增加了 “预提交阶段”,并引入超时机制:
- CanCommit 阶段:协调者询问参与者是否可执行事务(无实际操作);
- PreCommit 阶段:协调者确认所有参与者可执行后,通知其预提交(执行本地事务但未提交);
- DoCommit 阶段:协调者最终决定提交或回滚。
- 改进点:参与者在 PreCommit 阶段超时后可自主回滚,减少阻塞时间,但仍无法完全解决一致性问题,实际应用较少。
适用场景
2PC 适合对一致性要求高、并发量适中的场景,如:
- 银行转账、支付结算等金融业务(数据一致性优先于性能);
- 分布式数据库的跨节点事务(如 ShardingSphere 中的分布式事务实现)。
v1.3.10