Hello! Welcome to the next lesson in our journey through distributed databases.
In the last lesson, we explored how a single complex query, like a hash join, can be parallelized across many machines. We saw that the core challenge was shuffling data so that related information ends up on the same node for processing. Now, we're going to shift our focus from a single parallel query to a distributed transaction—an operation that needs to make changes on multiple database nodes and must succeed or fail as a single, atomic unit.
This brings us to a fundamental problem in distributed systems: how do you guarantee atomicity when any of the participating nodes, or the network itself, could fail? Today's lesson addresses this directly. Your learning outcome is to be able to describe the phases of the two-phase commit (2PC) protocol for distributed transactions. This classic algorithm is the foundation for achieving transactional guarantees in a distributed environment.
The Problem: Achieving Atomic Commitment
In a single-node database, transactions are atomic: they either commit all their changes or abort, leaving the database state untouched. In a distributed system, a single transaction might involve updates to several independent databases or services. For example, placing an order in an e-commerce system might require:
- Decrementing inventory in the
inventory-service. - Creating a charge in the
payment-service. - Recording the order in the
order-service.
If the payment service succeeds but the inventory service fails, you end up in an inconsistent state—charging a customer for an item that is out of stock. We need a way for all participants to agree on the final outcome: either they all commit, or they all abort. This is the atomic commitment problem.
To start, let's get a clear conceptual framing of this problem.
Distributed Systems 7.1: Two-phase commit
This video from Martin Kleppmann, an expert in distributed systems, introduces the concept of atomic commitment and distinguishes it from the related problem of consensus. This will help you understand the specific constraints that 2PC is designed to solve.
Please watch the segment from 02:28 to 06:34. Focus on why atomicity is essential for distributed transactions and the key difference between atomic commitment and general-purpose consensus algorithms like Raft.
As the video explains, unlike consensus where any proposed value can be chosen, atomic commitment has a strict rule: if even one participant votes to abort, the entire transaction must abort.
The Players and The Protocol
The Two-Phase Commit protocol formalizes this coordination. It involves two types of actors:
- The Coordinator: The single node that initiates the transaction and is responsible for making the final commit-or-abort decision. In our e-commerce example, this might be the
order-service. - The Participants: All the other nodes that are part of the transaction (e.g.,
inventory-service,payment-service).
The protocol unfolds in two distinct phases, as its name suggests. Let's walk through them. The state diagram below provides a formal view of the states and transitions for both the coordinator and a participant. We will refer to this as we discuss each phase.

Phase 1: The Prepare (or Voting) Phase
This phase is about checking if every participant is able and willing to commit.
- Coordinator sends
PREPARE: The Coordinator sends aPREPAREmessage to all Participants. This is the "get ready" signal. - Participants Prepare and Vote: Upon receiving
PREPARE, each Participant determines if it can commit the transaction. This isn't a hypothetical check. The Participant must perform all the necessary work, such as validating constraints and acquiring locks. Critically, it writes all its changes to a durable log (like a Write-Ahead Log) on disk.- If successful, the Participant has now made a binding promise. It is no longer allowed to unilaterally abort. It force-writes a
READYorPREPAREDrecord to its log and sends aVOTE-COMMITmessage back to the Coordinator. - If the Participant fails for any reason (e.g., a constraint violation), it can immediately decide to abort. It sends a
VOTE-ABORTmessage to the Coordinator.
- If successful, the Participant has now made a binding promise. It is no longer allowed to unilaterally abort. It force-writes a
The most important part of this phase is the promise made by participants who vote to commit. By writing their state to a durable log, they guarantee that they can still commit the transaction even if they crash and restart later.
Phase 2: The Commit (or Decision) Phase
The Coordinator now acts as the final arbiter based on the votes it received.
- Coordinator Makes a Decision:
- If the Coordinator receives
VOTE-COMMITfrom all Participants, it decides toCOMMIT. - If it receives even one
VOTE-ABORT, or if a participant times out, it decides toABORT.
- If the Coordinator receives
- Coordinator Logs and Broadcasts: The Coordinator force-writes its final decision (
COMMITorABORT) to its own durable log. This is crucial for its own recovery. It then broadcasts this decision message to all Participants. - Participants Execute the Decision: Upon receiving the decision from the Coordinator, each Participant:
- Writes the decision to its own log.
- If the decision is
COMMIT, it applies the changes from its log, making them permanent, and releases any locks. - If the decision is
ABORT, it uses its log to undo any changes and releases locks.
- Acknowledgment: After carrying out the decision, each Participant sends an
ACKmessage back to the Coordinator. Once the Coordinator has receivedACKs from all Participants, the protocol for that transaction is complete.
This sequence ensures that either all participants reach the committed state or all reach the aborted state.
To see a clear, step-by-step walkthrough of the messaging in both success and abort scenarios, please review the following diagrams from CMU's database course slides.
These slides from CMU provide simple, clear diagrams of the 2PC message flow for both a successful commit and an abort case. They perfectly illustrate the two phases we've just discussed.
Please examine slides 11 and 12 (labeled 'TWO-PHASE COMMIT (SUCCESS)' and 'TWO-PHASE COMMIT (ABORT)'). Trace the 'Prepare' and 'Commit'/'Abort' messages between the Coordinator and Participants.
An Engineering Perspective: 2PC in Practice
The abstract protocol of messages and logs is essential, but seeing how it maps to a real system makes it much more concrete. Given your background in C++, Java, and data structures, you'll appreciate how these concepts translate into service endpoints, database schemas, and SQL transactions.
The following video provides an excellent, applied walkthrough of 2PC using a food delivery service example. It demonstrates how RESERVE operations map to the prepare phase and ASSIGN operations map to the commit phase.
Implementing Distributed Transactions using Two Phase Commit Protocol
This video by Arpit Bhayani implements a 2PC protocol in Go for a practical use case. It's a fantastic demonstration of the engineering principles behind the protocol.
Please watch the following segments: Phases Explained (04:11 - 07:25): Understand how the abstract 'prepare' and 'commit' phases map to concrete 'reservation' and 'assignment' actions. Schema and Architecture (07:25 - 19:43): Pay close attention to the database schema design, especially the is_reserved flag, and how the Order Service acts as the coordinator making HTTP calls. Code Walkthrough (23:56 - 35:28): Focus on how the participant services (Delivery and Store) use SQL transactions and exclusive locks (SELECT ... FOR UPDATE) to atomically implement the reserve (prepare) step. This is a direct implementation of the 'promise' we discussed earlier.
This video nicely demonstrates how the is_reserved flag in the database is the physical manifestation of a resource being locked during the prepare phase, awaiting the final decision from the coordinator.
Test your understanding!
Imagine a participant in a 2PC transaction successfully completes its local work, writes a READY record to its log, and sends VOTE-COMMIT to the coordinator. Immediately after sending the vote, the participant node crashes and reboots. It has not yet received the final decision from the coordinator.
What should the participant do upon recovery? Can it decide to abort the transaction to free up its local resources? Why or why not?
Show answer
Upon recovery, the participant must check its log. It will find the READY record for the transaction. This means it made a promise to the coordinator that it is able to commit.
Therefore, it cannot unilaterally decide to abort. Aborting would break its promise and could lead to an inconsistent state if the coordinator had already decided to commit based on all participants' votes.
The participant is blocked. It must wait until it can contact the coordinator (or another participant, in some variants) to find out the final outcome of the transaction. The log is crucial because it reminds the recovered node of the promise it made before crashing.
The Achilles' Heel of 2PC: Blocking
The test-your-understanding question hints at the biggest weakness of the standard Two-Phase Commit protocol: it is a blocking protocol.
What happens if the Coordinator crashes?
- Case 1: Coordinator crashes before sending
PREPAREmessages. No problem, the transaction hasn't started. It can be aborted. - Case 2: Coordinator crashes after sending its final decision. Also no problem. When the coordinator recovers, it can read its decision from its log and re-send it to any participants who didn't
ACK. - Case 3 (The Bad One): Coordinator crashes after receiving votes but before writing and sending its final decision. In this scenario, all the participants who voted
VOTE-COMMITare now stuck. They have promised to commit and have locked resources, but they have no way of knowing the final decision. They are blocked until the coordinator recovers. If the coordinator is gone for good, these resources could be locked indefinitely, requiring manual intervention from a database administrator.
This blocking problem is a major trade-off for the consistency that 2PC guarantees.
Conclusion
In this lesson, we dissected the Two-Phase Commit protocol, the classic algorithm for ensuring atomic commitment in distributed systems.
Key Takeaways:
- Goal: To ensure a transaction spanning multiple nodes is atomic—all nodes either commit or all nodes abort.
- Roles: A central Coordinator drives the protocol, and multiple Participants carry out the work.
- Phase 1 (Prepare): The Coordinator asks participants to prepare. Participants do the work, write their changes to a durable log, and vote
COMMITorABORT. ACOMMITvote is a binding promise. - Phase 2 (Commit): The Coordinator makes a decision (commit only if all voted to commit). It logs the decision and broadcasts it. Participants then execute the decision.
- Implementation: In practice, the "prepare" phase often translates to reserving resources with locks (e.g.,
SELECT ... FOR UPDATE), while the "commit" phase involves finalizing the state changes.
Preview of the Next Lesson
We've just introduced the critical flaw in 2PC: the potential for blocking when the coordinator fails. In our next lesson, we will analyze these failure and blocking scenarios in the 2PC protocol in more detail. We'll explore the real-world impact of blocking on system availability and briefly touch upon alternative protocols, like Three-Phase Commit, that were designed to address this very issue.