The Distributed Atomicity Problem
A single-node database transaction is easy to make atomic: the storage engine either writes all the changes to disk or none of them, and a crash mid-write just gets rolled back on restart. Distributed transactions are harder because the work is split across multiple independent machines, each with its own local disk, its own clock, and its own chance of crashing or losing network connectivity at any moment. If a transaction updates data on three separate database nodes, you need all three updates to succeed together or all three to fail together atomicity across machines even though no single machine can see what the others are doing in real time. Without coordination, a partial failure (node A commits, node B crashes before it can) leaves the system in an inconsistent state: money debited from one account but never credited to another, an order marked as shipped in one service but never recorded as paid in the billing service. This is the core challenge two-phase commit was designed to solve: turning a set of independent, unreliable local decisions into one reliable, shared, all-or-nothing decision. The protocol introduces two roles to make this possible: a coordinator that drives the process and one or more participants that hold the actual data and do the real work of the transaction.
Phase 1: The Prepare and Vote
The first phase of 2PC is a voting round. The coordinator sends a prepare request to every participant, essentially asking, can you guarantee this transaction will succeed if I tell you to commit it later? Each participant then does the actual work of the transaction locally, applying the changes in a way that could still be undone, and critically, writes the outcome to a durable log on disk before responding. This durability step matters enormously: once a participant writes prepare to yes in its log, it is making a binding promise that it can commit later even if it crashes and restarts in the meantime, because it will replay the log and remember its promise. Each participant then replies with a vote: yes/ready meaning it has done the work, locked the necessary resources, and is fully prepared to commit, or no/abort meaning something went wrong, such as a constraint violation, a lock conflict, or a local failure, and the transaction cannot proceed. The coordinator collects every vote before moving forward. This phase essentially converts an uncertain future action into a certain, logged commitment, which is what makes the second phase trustworthy.
Phase 2: The Final Commit or Abort Decision
Once the coordinator has heard back from every participant, it makes the final call using a simple unanimous rule. If all participants voted yes, the coordinator writes its own decision to a durable log and then sends a commit message to every participant, who each finalize the transaction, release their locks, and make the changes permanently visible. If any single participant voted no, the coordinator instead sends an abort message to all participants, and every one of them rolls back the local changes it tentatively applied during phase 1, as if the transaction never happened. This unanimous-vote rule is what delivers atomicity: there is no path through the protocol where some participants commit while others abort, because the coordinator's single decision is broadcast to everyone and every participant is obligated to follow it. Participants acknowledge the final message, and only then does the coordinator consider the transaction fully closed. From the outside, the whole distributed transaction behaves like one atomic operation, even though it touched several independent machines that never directly coordinated with each other.
The Blocking Problem: A Critical Weakness
Two-phase commit reliably guarantees atomicity, but it has a well-known structural flaw called the blocking problem. Consider this scenario: three participants each vote yes during phase 1, writing that promise durably to their logs and locking their resources. The coordinator receives all three yes votes, and is about to send the commit message, but before it can send anything, it crashes, perhaps due to a hardware failure or network partition. Now every participant is stuck in an uncertain state. Each one has promised it can commit, so it cannot unilaterally abort, because the coordinator might have already decided to commit and told some other participant. But it also cannot unilaterally commit, because the coordinator might have been about to send an abort. The only safe option is to keep holding its locks, blocking any other transaction that needs those same resources, and wait for the coordinator to recover and tell it what to do. If the coordinator stays down for an extended period, those locks stay held the entire time, potentially freezing large parts of the system. This single point of failure, where the fate of many participants depends entirely on one coordinator's recovery, is the central criticism leveled at 2PC.
Motivating Three-Phase Commit and Consensus Protocols
The blocking problem directly motivated the search for more fault-tolerant alternatives. Three-phase commit (3PC) was an early attempt to fix it by inserting an additional pre-commit phase, giving participants enough shared knowledge that they can safely make progress on their own even if the coordinator disappears, though 3PC still struggles under network partitions and never saw the widespread adoption 2PC did. The more influential path forward turned out to be consensus algorithms like Paxos and Raft. Rather than relying on a single coordinator whose crash can freeze the whole system, these protocols replicate the decision itself across a cluster of nodes and only require a majority quorum to agree, not unanimous participation from every single node. If one node, even a leader, crashes, the remaining majority can still elect a new leader and keep making progress, because no single machine's failure can block the group indefinitely. This shift, from one fragile coordinator making a binding decision to a resilient quorum reaching agreement together, underlies how modern distributed databases, coordination services like ZooKeeper and etcd, and distributed consensus systems achieve both atomicity and high availability, directly addressing the weakness that classic two-phase commit could never fully escape.
Frequently asked questions
What is the main goal of two-phase commit?
The main goal is atomicity across multiple independent nodes in a distributed transaction: ensuring that every participant either commits the transaction together or every participant aborts it together, with no possibility of some nodes committing while others do not.
What is the difference between the coordinator and a participant?
The coordinator is the single node that drives the protocol, sending prepare requests, collecting votes, and broadcasting the final commit or abort decision. Participants are the nodes that actually hold the data, perform the transaction's work locally, vote on whether they can commit, and follow the coordinator's final instruction.
Why must participants write their vote to a durable log before responding?
Writing the vote durably ensures that if a participant crashes and restarts after voting yes, it can recover its promise from the log and still honor it later, rather than forgetting that it committed to being ready. This durability is what makes the yes vote a binding, trustworthy commitment.
What exactly is the blocking problem in two-phase commit?
The blocking problem occurs when the coordinator crashes after participants have voted yes but before it sends the final commit or abort decision. Those participants cannot safely proceed on their own in either direction, so they must hold their locks and wait, potentially for a long time, until the coordinator recovers.
How do Paxos and Raft avoid the blocking problem that two-phase commit has?
Paxos and Raft replicate decisions across a cluster and only require a majority quorum to agree rather than unanimous participation coordinated by one fragile node. If a leader node fails, the remaining majority can elect a replacement and keep making progress, so no single node's crash can freeze the entire system the way a coordinator crash can in classic two-phase commit.
Try it live
Everything above runs in your browser — open Two-Phase Commit: How Distributed Databases Agree to Commit or Abort Together and change the parameters while it is running. Nothing is installed, nothing is uploaded, the whole model lives in one tab.
▶ Open Two-Phase Commit: How Distributed Databases Agree to Commit or Abort Together simulation