← Back to list

Two-Phase Commit: The Good, the Bad, and the Blocking

Two-Phase Commit (2PC) is a distributed algorithm that ensures all participants in a transaction either commit or abort together. It is…

Sylvain Tiset · 2026-02-04 07:46 · 154 claps · 6.1 min read
#transactions #2pc #3pc #consensus #distributed-systems
Open on Medium ↗
Wiki topics: 💻 · Programming

Two-Phase Commit: The Good, the Bad, and the Blocking

Two-Phase Commit (2PC) is a distributed algorithm that ensures all participants in a transaction either commit or abort together. It is designed to provide atomicity in distributed systems, typically in databases, message queues, and microservices.

2PC in distributed systems (Generated by Microsoft Bing AI)

2PC in distributed systems (Generated by Microsoft Bing AI)

Distributed atomicity is the guarantee that a transaction spanning multiple machines either completes entirely or has no effect at all. In a single database, this guarantee is straightforward because all operations occur under one transaction manager with a unified log and lock system.

However, once data and operations are spread across multiple nodes, preserving this all-or-nothing behavior becomes significantly more complex. Each participant may have its own state, failure modes, and latency characteristics, making it difficult to ensure that they all reach the same outcome. The Two-Phase Commit (2PC) protocol was designed to address this problem.

How it works

2PC uses a central coordinator and several participants. These roles are logical, not tied to a specific technology, and can be implemented by database engines, transaction managers, services, or storage nodes. In short, any component capable of holding state and participating in a transaction.

It proceeds in two distinct phases :

  1. Prepare (Voting phase)
  2. Commit or Abort (Decision phase)

2PC example from media2.dev.to

2PC example from media2.dev.to

During the voting phase, the coordinator sends PREPARE request to all participants. Each participant then:

  • Executes the transaction up to the point of commit.
  • Records enough information in stable storage to commit later.
  • Replies with either: **VOTE_COMMIT (ready to commit), or `VOTE_ABORT`** (unable to commit: conflict, crash, constraint violation, etc.)

If any participant votes abort, or if any participant fails to respond, the coordinator decides to abort the entire transaction.

During decision phase, if any participant voted ABORT:

  1. The coordinator writes “abort” to its log
  2. The coordinator sends **GLOBAL_ABORT** to all participants.
  3. Participants abort the transaction and free resources.

On the other hand, if all participants voted for COMMIT:

  1. The coordinator writes “commit” to its log
  2. The coordinator sends **GLOBAL_COMMIT** to all participants.
  3. Each participant commits the transaction and acknoledges completion.

Limitations

If the coordinator crashes after sending PREPARE but before sending the final decision, participants may be stuck waiting indefinitely. This is the most serious weakness of 2PC.

Additionnaly, there is no built-in recovery from coordinator failure: participants cannot autonomously decide to commit/abort safely. They must wait for the coordinator to recover and tell them.

More generally, the coordinator node is a single point of failure in the 2PC protocol. If the coordinator fails, the entire transaction fails, and the system will need to restart the transaction from scratch.

Every decision requires two network round trips. The 2PC protocol becomes increasingly difficult to scale in large distributed systems. As the number of participants grows, the amount of coordination and message exchange required between nodes increases significantly, leading to substantial communication overhead.

Both coordinator and participants must persist durable logs, using Write-Ahead Logging (WAL). The 2PC protocol can have a significant impact on the performance of the system, particularly in high write throughput scenarios.

The Three-Phase Commit (3PC) protocol is an evolution of the Two-Phase Commit protocol designed to reduce the risk of blocking caused by coordinator failures.

A word on 3PC

How 3PC Works

Phase 1: CanCommit (Similar to 2PC Prepare)

Phase 2: PreCommit

If all votes are Yes:

The Coordinator sends a “PreCommit” message.

Participants then:

  • Prepare to commit.
  • Write a “pre-commit” record to stable storage.
  • Acknowledge the coordinator.

This phase ensures participants know that everyone else has voted Yes and that the coordinator has decided to commit — but the commit is not executed yet.

Phase 3: DoCommit

Once all participants acknowledge the PreCommit:

  • Coordinator sends “DoCommit”.
  • Each participant commits the transaction.

If the coordinator fails at this stage, participants have enough information to decide safely on their own.

3PC example from media2.dev.to

3PC example from media2.dev.to

What 3PC Solves Compared to 2PC

It eliminates the blocking problem. 2PC can block if:

  • Participants voted commit (in the “prepared” state),
  • Coordinator crashes before sending the final decision.

3PC avoids this because:

  • After PreCommit, participants know the system reached a unanimous decision.
  • They can use timeouts and state knowledge to commit autonomously if the coordinator disappears.

Result: 3PC is non-blocking — as long as the network is reliable enough to respect timeouts.

However, 3PC is not really used in real distributed systems because:

  • It relies on network synchrony assumptions: timeout-based correctness requires guaranteed message delivery within known bounds (rare in real-world asynchronous networks).
  • It still cannot handle partitioned networks reliably. Even worse, if the network splits, different partitions may reach different conclusions. In a partitioned network, some nodes cannot communicate with others even though they are still running. This creates a dangerous situation for 3PC (and 2PC as well): different groups of participants may not receive the same messages at the same time. Because 3PC relies on timeouts and local decisions during those timeouts, two partitions may independently decide different outcomes for the same transaction.
  • Modern consensus algorithms (like Paxos and Raft) replaced it and do even better.

Thus, 3PC is mostly of theoretical interest.

Comparison with Modern Approaches

2PC vs. consensus (Paxos, Raft)

While 2PC ensures atomic commit across multiple participants, it does so with a single coordinator that can become a blocking point if it fails. Consensus algorithms like Paxos and Raft, by contrast, are designed to maintain availability and safety even under node failures and network partitions.

They replicate state across a quorum of nodes and can elect a new leader if the current one fails, allowing the system to continue making progress.

In modern distributed databases and configuration stores, consensus is often used as the foundation for fault-tolerant coordination, something 2PC cannot provide on its own.

2PC vs. distributed transactions in NoSQL

Many NoSQL systems avoid 2PC entirely because its coordination overhead and blocking behavior conflict with their goals of high availability and horizontal scalability (CAP theorem).

Instead, these systems typically rely on partitioned data models, eventual consistency or conditional writes. 2PC-style global transactions are generally avoided because they impose latency and failure sensitivity that contradict NoSQL’s distributed design philosophy.

2PC vs. Saga pattern in microservices

In microservices architectures, 2PC is rarely used because it tightly couples services and forces them to hold locks or resources while waiting on a coordinator.

The Saga pattern offers a more resilient alternative: instead of atomic commit, it uses a sequence of local transactions with compensating actions to undo work if a step fails.

This approach favors availability and decoupling at the cost of weaker consistency guarantees. Sagas embrace the inherent uncertainty of distributed systems, whereas 2PC tries to hide it behind strict coordination, making Sagas more suitable for large-scale, loosely coupled service ecosystems.

2PC real use cases

Despite its limitations, 2PC remains valuable in systems that require strong consistency and operate in relatively stable, well-controlled environments. It is appropriate when the number of participants is small, network reliability is high, and strict atomicity is more important than availability.

Distributed SQL (PostgreSQL FDW, MySQL XA)

Distributed SQL systems and traditional relational databases often use 2PC to guarantee atomicity across multiple storage engines or nodes. PostgreSQL’s Foreign Data Wrapper (FDW) framework and MySQL’s XA transactions both rely on variants of the two-phase commit protocol to coordinate commits across different backends.

In these environments, the number of participants is limited and the network conditions are controlled, making 2PC’s blocking behavior acceptable.

The protocol ensures that multi-database or multi-shard operations either fully commit or fully roll back, maintaining strong transactional integrity.

Message brokers (JMS, Kafka transactions)

Some messaging systems use 2PC to ensure exactly-once guarantees between a producer, a message broker, and downstream consumers.

In traditional Java Message Service (JMS) infrastructures, 2PC is used to coordinate between application servers and message queues to ensure messages are delivered atomically with related database updates.

Kafka transactions follow similar principles, using a coordinator to guarantee atomic writes across partitions. While not a pure classical 2PC implementation, the design borrows heavily from the same commit-phase logic to ensure that a batch of messages is either fully visible or fully discarded.

Enterprise systems requiring strict consistency

Large enterprise platforms (banking systems, financial ledgers, inventory management systems, and ERP platforms) frequently rely on 2PC when strict consistency and transactional correctness outweigh availability concerns.

These systems often operate within controlled datacenter environments with well-defined operational procedures, making the risk of coordinator blocking more manageable.

In these cases, 2PC provides a clear and time-tested mechanism to enforce atomic multi-resource updates, ensuring the system’s overall correctness even under complex transactional workloads.

Hoping 2PC algorithm has no more secrets to you. If you liked this article, feel free to clap it, comment it or share it. To stay updated with my content, you can follow me on Medium.


메타데이터
post_id
eee29e1f5a84
slug
two-phase-commit-the-good-the-bad-and-the-blocking-eee29e1f5a84
url
https://medium.com/@sylvain.tiset/two-phase-commit-the-good-the-bad-and-the-blocking-eee29e1f5a84
canonical_url
https://medium.com/@sylvain.tiset/two-phase-commit-the-good-the-bad-and-the-blocking-eee29e1f5a84
author_url
https://medium.com/@sylvain.tiset
status
ok
fetched_at
2026-06-26 03:39:16