Module 14 · Distributed transactions · Lesson 3 of 5
Three-phase commit
An attempt to remove 2PC's blocking by adding a pre-commit phase so participants can decide without the coordinator. Why it works under a synchronous network with crash failures only, why network partitions break it.
Why it matters
Three-phase commit is the textbook answer to 2PC's blocking problem, and it appears in interviews mostly as a trap: candidates who present it as the fix reveal that they have not thought about partitions. Knowing precisely what it fixes, what it assumes, and why practitioners replaced the idea with consensus is the useful outcome of this lesson.
The idea
2PC blocks because a participant that voted yes cannot tell whether the coordinator decided commit or abort. Three-phase commit inserts a phase between the vote and the commit so that no participant is ever in a state where both outcomes remain possible for the group.
- 1
Phase 1: can-commit
The coordinator asks each participant whether it can commit; participants vote yes or no without yet writing redo records or locking for the long term. - 2
Phase 2: pre-commit
If all voted yes, the coordinator sends pre-commit; participants prepare durably and acknowledge. Now every participant knows that every other participant voted yes, because pre-commit is only sent when they all did. - 3
Phase 3: do-commit
The coordinator sends commit; participants commit and acknowledge.
The non-blocking property comes from this: if a participant has received pre-commit, it knows all votes were yes, so on coordinator failure the survivors can safely elect a new coordinator and commit. If a participant has not received pre-commit, no participant can have committed yet, so survivors can safely abort. There is no state in which some participants might have committed while others might have to abort, under the protocol's assumptions.
The assumption that breaks it
3PC is non-blocking only under a synchronous model: bounded message delay and bounded processing time, so that a timeout reliably means a crash, and crash failures only, no partitions. Under a network partition, participants on one side may have received pre-commit (and proceed to commit) while participants on the other side timed out before receiving it (and abort). Both sides act correctly by the protocol and the result is a non-atomic outcome, which is worse than 2PC's blocking: 2PC blocked but stayed correct; 3PC stays live and becomes wrong. Since partitions are a fact of real networks, 3PC is essentially never deployed.
What replaced the idea
The modern approach keeps 2PC's correctness and removes the coordinator as a single point of blocking by replicating the coordinator's state with consensus. The commit decision is written to a Paxos or Raft group rather than one node's log, so coordinator failure is a leader failover measured in seconds and in-doubt participants can always learn the decision from the surviving majority. Spanner's 2PC over Paxos groups and Paxos Commit are this design. The extra network round of 3PC is replaced by the consensus round that makes the decision durable and available.
| 2PC | 3PC | 2PC over consensus | |
|---|---|---|---|
| Blocking on coordinator failure | Yes, until it recovers | No, under synchrony | Only until the consensus group elects a new leader |
| Correct under partition | Yes (blocks) | No (can diverge) | Yes (minority side blocks, majority continues) |
| Message rounds | 2 | 3 | 2 plus consensus rounds for the decision |
| Used in practice | Yes | Essentially never | Yes: Spanner, CockroachDB, TiDB |
What to take from it
The lesson of 3PC is general: a protocol's guarantees are only as good as its failure model. "Non-blocking" was bought by assuming timeouts are perfect failure detectors, which the earlier lessons showed they are not. Whenever a design claims to have removed a trade-off, ask what it assumes about the network.