Two-Phase Commit
- Pradeep P
- 3 days ago
- 3 min read
Series: Modern System Design · Layer 4 — Data
Layer 4 · Post 7 of 11
← Previous: Distributed Transactions → Next: Sagas
Layer 4 — Data · Post 46 of 88
Two-phase commit is the classic algorithm for distributed transactions: vote first, then commit. If a participant stalls, everyone can get stuck.
What you'll learn
The prepare/vote then commit/abort dance, including what "in doubt" means
Why the coordinator is a stall point, and why 3PC/Paxos commit exist
When XA/2PC is still the right tool — and when you should reach for a saga instead
The idea in one minute
Two-phase commit (2PC) is how several databases try to act like one transaction.
Phase 1 — prepare (vote): the coordinator asks every participant, "Can you commit this?" Each writes enough to durable storage to promise either commit or abort later, then answers yes or no.
Phase 2 — commit (or abort): if everyone said yes, the coordinator records the decision and tells them commit. If anyone said no, everyone aborts.
Coordinator --> PREPARE --> DB-A, DB-B DB-A, DB-B --> YES/NO --> Coordinator Coordinator --> COMMIT --> DB-A, DB-B (only if all YES)
Until phase 2 arrives, a participant that voted yes is in doubt: it must not forget the transaction and must not unilaterally commit. If the coordinator dies here, those rows stay locked. That is the famous 2PC failure mode.
Why it matters
This is the algorithm behind XA transactions: one COMMIT in the app server, two resource managers. Interviewers use 2PC to test whether you understand blocking atomic commit versus "we will just retry."
You need it in your vocabulary even if you will recommend sagas for most HTTP/microservice designs. Spanner-style systems still run a cousin of atomic commit inside the database. You are not above this problem; you outsourced it.
How it works
Each participant's prepare is a local durability barrier: redo/undo is on disk, locks are held. The coordinator's decision must also be durable — otherwise it recovers and picks the opposite choice.
Failure cases you should name:
Participant says no → abort everyone. Easy.
Participant never answers → coordinator times out, aborts (if it has not decided commit).
Coordinator dies after logging COMMIT but before some participants hear it → those participants stay in doubt until a new coordinator reads the log and re-sends the decision.
Participant dies after prepare, before commit → on restart it asks the coordinator "what was decided?"
Three-phase commit tries to reduce blocking; it adds another round and still struggles with partitions. Modern systems prefer consensus (Paxos/Raft) to agree on the decision, then tell participants. Same idea, better failure story, still latency.
A simple example
A Java service updates Postgres (orders) and publishes to an XA-capable JMS broker in one JTA transaction. Prepare succeeds on both. The app server crashes before commit messages go out. Postgres holds row locks on the order. The message is not visible. Operators run xa recover / heuristic commit. That is 2PC in production, not a textbook.
You cannot run this protocol against Stripe's API. Stripe will not enter your prepare phase.
Common mistakes
2PC across high-latency or untrusted participants. Cloud APIs, mobile clients, and Kafka (as usually deployed) are the wrong voters.
Ignoring lock duration. Prepare holds locks until commit. Slow participants stall everyone else's writes.
Heuristic decisions. An admin force-commits one side. You have now invented split-brain by hand. Log it and reconcile.
Calling Kafka + DB "2PC" because both writes are in a try block. That is dual write.
How this shows up in real systems
XA / JTA / MSDTC: classic 2PC across databases and queues.
MySQL XA, Postgres PREPARE TRANSACTION: available; operationally sharp.
Spanner, CockroachDB, Yugabyte: per-statement distributed commit inside the product.
DynamoDB transactions: internal coordination; you are not the coordinator.
Recap
2PC: vote, then decide. Atomic when it works; blocking when the coordinator or a prepared participant vanishes.
Use it inside a platform you control, not across HTTP vendors.
Most product flows prefer sagas: local commits plus compensation. That is next.
Series: Modern System Design · Layer 4 — Data
Layer 4 · Post 7 of 11
← Previous: Distributed Transactions → Next: Sagas



Comments