← Back to list

Understanding 2-Phase Commit Protocol in Distributed Transactions

Introduction

Spring Boot Simplified · 2025-10-01 10:06 · 31 claps · 5.6 min read
#2pc #java #spring-boot #spring-training #spring-framework
Open on Medium ↗

Understanding 2-Phase Commit Protocol in Distributed Transactions

Introduction

In modern distributed systems, maintaining data consistency across multiple services is one of the most challenging problems. When a business transaction spans multiple databases or services, we need to ensure that either all operations succeed or all fail — there’s no middle ground. This is where the Two-Phase Commit (2PC) protocol comes into play.

In this article, we’ll explore the 2PC protocol using a real-world e-commerce scenario: processing an order that involves coordinating between Order Management, Inventory, and Payment services.

The Problem: Distributed Transactions

Imagine an e-commerce platform where placing an order requires:

  1. Creating an order record (Order Management Service)
  2. Reserving inventory (Inventory Service)
  3. Processing payment (Payment Service)

If any of these operations fails, we need to rollback all changes to maintain consistency. In a monolithic application with a single database, this is straightforward using ACID transactions. But in a distributed system where each service has its own database, traditional transactions don’t work across service boundaries.

What is Two-Phase Commit?

The Two-Phase Commit protocol is a distributed algorithm that ensures all participants in a distributed transaction either commit or abort the transaction atomically. It works through a coordinator (in our case, Order Management Service) that orchestrates the transaction across multiple participants (Inventory and Payment Services).

The protocol consists of two distinct phases:

Phase 1: Prepare Phase (Voting Phase)

In this phase, the coordinator asks all participants if they’re ready to commit the transaction.

┌─────────────────────────────────────────────────────────────┐
│                      PHASE 1: PREPARE                        │
└─────────────────────────────────────────────────────────────┘
     Order Management Service (Coordinator)
                    │
                    │ 1. PREPARE Request
                    ├────────────────────────┐
                    │                        │
                    ▼                        ▼
          Inventory Service          Payment Service
                    │                        │
          2. Check if can                2. Check if can
             reserve items                  process payment
                    │                        │
          3. Lock resources              3. Lock resources
             (tentative)                    (tentative)
                    │                        │
          4. Write to                    4. Write to
             transaction log                transaction log
                    │                        │
                    ▼                        ▼
          VOTE: YES/NO               VOTE: YES/NO
                    │                        │
                    └────────┬───────────────┘
                             │
                             ▼
                Order Management Service
                  (Collects all votes)

What happens in Prepare Phase:

  1. Coordinator sends PREPARE: Order Management sends a prepare request to both Inventory and Payment services
  2. Participants validate: Each service checks if it can complete its part of the transaction
  • Inventory: Can we reserve the requested items?
  • Payment: Can we process this payment amount?
  1. Resource locking: If validation succeeds, each service locks the necessary resources
  2. Logging: Each participant writes the transaction details to a persistent log (for recovery)
  3. Voting: Each participant responds with:
  • YES (PREPARED): Ready to commit, resources locked
  • NO (ABORT): Cannot complete, transaction should abort

Phase 2: Commit/Abort Phase (Decision Phase)

Based on the votes received, the coordinator makes a final decision and instructs all participants accordingly.

┌─────────────────────────────────────────────────────────────┐
│                   PHASE 2: COMMIT/ABORT                      │
└─────────────────────────────────────────────────────────────┘
     Order Management Service (Coordinator)
                    │
         Decision:  │
         - All YES → COMMIT
         - Any NO  → ABORT
                    │
                    │ COMMIT/ABORT Command
                    ├────────────────────────┐
                    │                        │
                    ▼                        ▼
          Inventory Service          Payment Service
                    │                        │
          Execute final                 Execute final
          operation                     operation
                    │                        │
          Release locks                Release locks
                    │                        │
          Log completion               Log completion
                    │                        │
                    ▼                        ▼
               ACK to                    ACK to
             Coordinator               Coordinator
                    │                        │
                    └────────┬───────────────┘
                             │
                             ▼
                Order Management Service
                  (Transaction Complete)

What happens in Commit Phase:

  1. Coordinator decides:
  • If ALL participants voted YES → Send COMMIT
  • If ANY participant voted NO → Send ABORT
  1. Participants execute: Each service either commits or rolls back
  2. Release resources: Locks are released
  3. Acknowledgment: Participants send ACK back to coordinator
  4. Completion: Coordinator marks transaction as complete

Real-World Example: Order Processing Flow

Let’s walk through a complete order processing scenario:

Scenario: Customer orders 2 laptops for $2000

┌──────────────────────────────────────────────────────────────┐
│              SUCCESSFUL TRANSACTION FLOW                      │
└──────────────────────────────────────────────────────────────┘
[Customer] 
    │
    │ POST /orders (2 laptops, $2000)
    ▼
[Order Management Service] - COORDINATOR
    │
    │ Transaction ID: TXN-12345
    │
    ├─ PHASE 1: PREPARE ─────────────────────────────────────┐
    │                                                          │
    │ "Can you reserve 2 laptops?"                           │
    ├──────────────────────────►[Inventory Service]          │
    │                                  │                      │
    │                                  ├─ Check stock: 5 available
    │                                  ├─ Lock 2 laptops     │
    │                                  ├─ Log: TXN-12345     │
    │                                  │                      │
    │                           ◄──────┤ VOTE: YES           │
    │                                                          │
    │ "Can you process $2000 payment?"                       │
    ├──────────────────────────►[Payment Service]            │
    │                                  │                      │
    │                                  ├─ Check balance: OK  │
    │                                  ├─ Hold $2000         │
    │                                  ├─ Log: TXN-12345     │
    │                                  │                      │
    │                           ◄──────┤ VOTE: YES           │
    │                                                          │
    ├─ Decision: ALL YES → COMMIT ────────────────────────────┤
    │                                                          │
    ├─ PHASE 2: COMMIT ───────────────────────────────────────┤
    │                                                          │
    │ "COMMIT"                                                │
    ├──────────────────────────►[Inventory Service]          │
    │                                  │                      │
    │                                  ├─ Deduct 2 laptops   │
    │                                  ├─ Release locks       │
    │                                  │                      │
    │                           ◄──────┤ ACK                  │
    │                                                          │
    │ "COMMIT"                                                │
    ├──────────────────────────►[Payment Service]            │
    │                                  │                      │
    │                                  ├─ Charge $2000       │
    │                                  ├─ Release holds       │
    │                                  │                      │
    │                           ◄──────┤ ACK                  │
    │                                                          │
    │ Update order status: CONFIRMED                          │
    │                                                          │
    ▼                                                          │
[Customer] ◄─ Order Confirmed                                 │
    │                                                          │
    └──────────────────────────────────────────────────────────┘

Failure Scenario: Insufficient Inventory

┌──────────────────────────────────────────────────────────────┐
│              FAILURE TRANSACTION FLOW                         │
└──────────────────────────────────────────────────────────────┘
[Customer] 
    │
    │ POST /orders (5 laptops, $5000)
    ▼
[Order Management Service] - COORDINATOR
    │
    ├─ PHASE 1: PREPARE ─────────────────────────────────────┐
    │                                                          │
    │ "Can you reserve 5 laptops?"                           │
    ├──────────────────────────►[Inventory Service]          │
    │                                  │                      │
    │                                  ├─ Check stock: Only 3 available
    │                                  │                      │
    │                           ◄──────┤ VOTE: NO            │
    │                                                          │
    │ "Can you process $5000 payment?"                       │
    ├──────────────────────────►[Payment Service]            │
    │                                  │                      │
    │                                  ├─ Check balance: OK  │
    │                                  ├─ Hold $5000         │
    │                                  │                      │
    │                           ◄──────┤ VOTE: YES           │
    │                                                          │
    ├─ Decision: ANY NO → ABORT ──────────────────────────────┤
    │                                                          │
    ├─ PHASE 2: ABORT ────────────────────────────────────────┤
    │                                                          │
    │ "ABORT"                                                 │
    ├──────────────────────────►[Inventory Service]          │
    │                                  │                      │
    │                                  ├─ No action needed   │
    │                                  │                      │
    │                           ◄──────┤ ACK                  │
    │                                                          │
    │ "ABORT"                                                 │
    ├──────────────────────────►[Payment Service]            │
    │                                  │                      │
    │                                  ├─ Release hold       │
    │                                  │                      │
    │                           ◄──────┤ ACK                  │
    │                                                          │
    │ Update order status: FAILED                             │
    │                                                          │
    ▼                                                          │
[Customer] ◄─ Order Failed: Insufficient Inventory            │
    │                                                          │
    └──────────────────────────────────────────────────────────┘

Minimal Java Implementation Structure

Here’s a high-level view of how this would be structured in Java (interface-level only):

Coordinator Interface

public interface TransactionCoordinator {
    // Initiate 2PC protocol
    TransactionResult executeTransaction(TransactionContext context);

    // Phase 1: Send prepare to all participants
    Map<String, VoteResponse> preparePhase(String transactionId);

    // Phase 2: Send commit/abort based on votes
    void commitPhase(String transactionId, boolean commit);
}

Participant Interface

public interface TransactionParticipant {
    // Phase 1: Prepare to commit
    VoteResponse prepare(TransactionContext context);

    // Phase 2: Commit the transaction
    void commit(String transactionId);

    // Phase 2: Rollback the transaction
    void abort(String transactionId);
}

Order Management Service (Coordinator)

@Service
public class OrderManagementService implements TransactionCoordinator {

    @Autowired
    private InventoryServiceClient inventoryService;

    @Autowired
    private PaymentServiceClient paymentService;

    public OrderResult processOrder(OrderRequest request) {
        String txnId = generateTransactionId();

        // Phase 1: Prepare
        boolean inventoryReady = inventoryService.prepare(txnId, request.getItems());
        boolean paymentReady = paymentService.prepare(txnId, request.getAmount());

        // Phase 2: Decide and execute
        if (inventoryReady && paymentReady) {
            inventoryService.commit(txnId);
            paymentService.commit(txnId);
            return OrderResult.success();
        } else {
            inventoryService.abort(txnId);
            paymentService.abort(txnId);
            return OrderResult.failure();
        }
    }
}

Advantages of 2-Phase Commit

  1. Strong Consistency: Guarantees all-or-nothing transaction semantics
  2. ACID Properties: Maintains atomicity across distributed systems
  3. Well-Understood: Mature protocol with clear semantics
  4. Fault Tolerance: With proper logging, can recover from failures

Disadvantages of 2-Phase Commit

  1. Blocking Protocol: If coordinator crashes after prepare phase, participants remain blocked
  2. Performance Overhead: Multiple round-trips increase latency
  3. Single Point of Failure: Coordinator is critical; its failure affects entire system
  4. Resource Locking: Locks held during both phases can reduce throughput
  5. Not CAP-Friendly: Chooses consistency over availability

When to Use 2-Phase Commit

Good Use Cases:

  • Financial transactions requiring strict consistency
  • Systems where data accuracy is more important than availability
  • Internal microservices within same datacenter with low latency
  • Scenarios with infrequent writes

Avoid When:

  • High-availability is critical
  • Services are geographically distributed
  • High transaction volume
  • Network partitions are common

Alternatives to Consider

  1. Saga Pattern: Choreographed compensating transactions
  2. Event Sourcing: Append-only event log with eventual consistency
  3. Try-Confirm/Cancel (TCC): Variant of 2PC with explicit cancel
  4. Distributed Locks: For simpler coordination scenarios

Best Practices

  1. Implement Timeouts: Prevent indefinite blocking
  2. Transaction Logs: Essential for recovery and debugging
  3. Idempotency: Make commit/abort operations idempotent
  4. Monitoring: Track transaction states and failures
  5. Circuit Breakers: Prevent cascading failures
  6. Keep Transactions Short: Minimize lock duration

Conclusion

The Two-Phase Commit protocol is a powerful tool for maintaining consistency in distributed transactions. While it has limitations — particularly around availability and performance — it remains relevant for scenarios demanding strong consistency guarantees.

For our order management example, 2PC ensures that an order is only confirmed when both inventory is reserved and payment is processed successfully. This prevents scenarios like charging customers for out-of-stock items or reserving inventory without payment.

However, modern distributed systems often favor eventual consistency and alternatives like the Saga pattern. The choice between 2PC and other patterns depends on your specific requirements around consistency, availability, and partition tolerance — the classic CAP theorem tradeoffs.

Understanding 2PC provides a solid foundation for reasoning about distributed transactions and helps you make informed architectural decisions for your systems.

Have you implemented 2PC in your systems? What challenges did you face? Share your experiences in the comments!


메타데이터
post_id
d97efb5caa39
slug
understanding-2-phase-commit-protocol-in-distributed-transactions-d97efb5caa39
url
https://medium.com/@aravindcsebe/understanding-2-phase-commit-protocol-in-distributed-transactions-d97efb5caa39
canonical_url
https://medium.com/@aravindcsebe/understanding-2-phase-commit-protocol-in-distributed-transactions-d97efb5caa39
author_url
https://medium.com/@aravindcsebe
status
ok
fetched_at
2026-06-26 03:39:16