两阶段提交(2PC)与三阶段提交(3PC)

05-事务与数据系统 核心 约 20 分钟 #2PC#XA#分布式事务#三阶段提交 更新 2026-10-02
当前状态:未学
本文基于模型知识整理(生成时未联网核对),关键结论建议对照经典文献复核。

一句话定义

两阶段提交(2PC)用"先投票承诺、再统一决定"把跨多个节点的原子提交做出来:全员同意才提交、任一反对即中止;代价是协调者单点与阻塞窗口——协调者在投票后崩溃,全体参与者只能锁着资源等它回来。

为什么重要

2PC 是唯一能跨异构资源(数据库+消息+缓存)提供强原子性的通用协议(XA 标准),也是所有"柔性事务"方案(kp-024)的对照原点。理解它为什么阻塞、为什么与共识形似神异,才能在强一致与高可用之间做出正确架构选择。

前置知识

kp-019(日志与提交语义)、单机事务 ACID。

核心概念

  • Phase 1(prepare/vote):协调者询问所有参与者能否提交;参与者把 undo/redo 日志落盘后回复 yes/no——yes 是不可撤销的承诺。
  • Phase 2(commit/abort):全员 yes → 协调者发 commit;任一 no 或超时 → abort。参与者执行决定并清理日志。
  • 不确定窗口(in-doubt):参与者投了 yes 之后、收到 Phase 2 决定之前,它不能单方面决定(单方面提交可能与其他参与者 abort 矛盾;单方面 abort 则违背已投出的承诺),只能阻塞等协调者。
  • 3PC:把 Phase 2 拆成 pre-commit(先同步"将要提交")与 commit,并引入超时默认动作,试图消除阻塞;但分区下仍可能出现两分支各自"提交/中止"的不一致,且多一轮 RTT,实践罕见。

原理与机制

阻塞的根源:决定权收敛到协调者却没有任何参与者能代替它。参与者已 yes 但没收到第二阶段消息时,处于"不确定"状态:此时它若自行 abort,而协调者其实已发出 commit(部分参与者已提交),原子性被破坏;若自行 commit,协调者可能已 abort。所以唯一安全动作是等待——这正是 2PC 在协调者故障时"全员卡死"的机制本质。

2PC ≠ Paxos(形似神异):两者都是两阶段投票,但 2PC 的 Phase 1 承诺的是"我这边准备好了"(资源锁住),参与者没有否决已承诺结果的能力,协调者死掉就死锁;Paxos 的多数派规则允许新 leader 重建决定,无阻塞。因此高可用的原子提交 = 2PC 的语义 + 共识的容错 = 每一步决定都过共识(Spanner/TiDB 的做法:协调者状态与参与者决策日志都放 Raft 组里,kp-032)。

性能:两次"全参与者 RTT" + 准备阶段锁持有时间 = 事务关键路径被最慢参与者绑架;这也是微服务架构普遍回避 XA、转向最终一致的原因之一。

图示

协调者                参与者A        参与者B
  │──prepare──────►   锁资源,写日志   锁资源,写日志
  │◄──────yes──────────│──────────────│
  │◄──────yes──────────(B 也 yes)
  │──commit───────►    提交           提交
  ✗ 若协调者在两阶段间崩溃:
    A、B 持锁进入 in-doubt,只能等待 → 阻塞

直观类比

婚礼司仪问双方"愿意吗"(prepare,双方承诺后不许反悔);司仪宣布"结为夫妻"(commit)。司仪说完第一阶段就晕倒了:新郎新娘(参与者)既不能私自结婚也不能私自散伙——只能原地等司仪醒来(阻塞)。

实例或案例

  • XA / JTA:Java 生态跨库事务标准,金融存量系统仍在用;运维痛点正是 in-doubt 事务清理。
  • MySQL XA:XA START/PREPARE/COMMIT;与 binlog 复制互动的细节曾长期是坑。
  • Kafka 事务:本质是"向事务协调者 + 多分区日志"的 2PC 变体,配合幂等生产者实现跨分区原子写。
  • 跨库扣款:传统方案 XA;互联网方案多为 Saga/TCC(kp-024)以换可用性。

常见误区

  • 误区一:"2PC 是容错的"。它只保证原子性语义(要么都成要么都不成),不保证可用性——协调者崩溃即阻塞;容错版需要共识加持。
  • 误区二:"3PC 解决了 2PC 的问题"。3PC 在网络分区下会脑裂(两侧各自推进),用不一致风险换阻塞减少,得不偿失,生产几乎不用。
  • 误区三:"同步链路里加 XA 没代价"。prepare 阶段锁资源直到 commit,长事务会把锁持有时间放大数倍,吞吐骤降。

与其他知识点的关系

  • kp-017/019:共识如何为提交决定加容错(原子提交 = 2PC + 共识)。
  • kp-024:以补偿换可用性的柔性事务谱系。
  • kp-027:Spanner 将 2PC 与 Paxos、TrueTime 组合的全局事务实现。

自测题

  1. 参与者投 yes 后协调者失联,它为什么不能自行决定?

答:它不知道其他参与者收到的是 commit 还是 abort;自行提交可能与其他 abort 分支矛盾,自行中止则违背承诺,任何单方动作都可能破坏原子性,只能等待。

  1. 2PC 与 Paxos 都两阶段,本质差别?

答:Paxos 的多数派让新 leader 可重建决定(无阻塞),2PC 的决定权收敛在协调者且参与者无更替能力(会阻塞);容错原子提交需把 2PC 的每步决定放上共识。

  1. 3PC 为什么被淘汰?

答:为消除阻塞引入 pre-commit 与超时默认,但分区时两个分支可分别推进到提交与中止,引入不一致风险,且多一轮延迟,收益不抵代价。

延伸阅读

  • Jim Gray, "Notes on Data Base Operating Systems"(1978,2PC 原始表述)。
  • Philip Bernstein 等《Principles of Transaction Processing》。
  • Spanner 论文对"2PC + Paxos"组合的论述(kp-032 延伸)。