Saga vs Two-Phase Commit (2PC)¶
1. Decision¶
Choose Two-Phase Commit (2PC) for strict ACID transactional consistency across tightly coupled homogeneous database nodes where blocking locks and high network availability are acceptable; choose the Saga Pattern (Choreography or Orchestration) for distributed transactions across independent microservices and heterogeneous databases where loose coupling, high availability, and eventual consistency are required.
2. 30-Second Answer¶
Managing distributed transactions across multiple microservices or database shards requires choosing between 2PC and Saga. Two-Phase Commit (2PC) is a synchronous protocol where a central Coordinator coordinates a Prepare Phase and Commit Phase across participating nodes. 2PC guarantees strict ACID isolation across databases, but holds blocking locks on resources, creating a single point of failure (coordinator dependency) and severe latency degradation. Saga Pattern breaks a global transaction into a sequence of local ACID transactions executed by independent microservices. Each local transaction updates its local database and emits an event. If a step fails, the Saga executes explicit Compensating Transactions in reverse order to roll back state. Saga trades ACID isolation for eventual consistency and high availability.
3. Decision Matrix¶
| Option | Best For | Avoid When | Latency | Scalability | Consistency | Operational Complexity |
|---|---|---|---|---|---|---|
| Two-Phase Commit (2PC) | Tightly coupled homogeneous database shards (XA transactions, Spanner), short-lived distributed ACID updates | Independent microservice architectures, high-scale internet traffic, heterogeneous polyglot databases | High (Synchronous multi-roundtrip blocking network locks) | Low (Blocking locks reduce cluster concurrency; coordinator SPOF) | Strict ACID (Immediate global consistency) | High (Coordinator failover, lock management) |
| Saga (Choreography) | Simple event-driven microservice workflows (2-4 steps), asynchronous event-bus architectures | Complex workflows with 10+ steps (becomes impossible to trace event cascades) | Low (Asynchronous non-blocking execution) | High (Decoupled independent microservices) | Eventual Consistency (Compensating rollbacks) | Medium |
| Saga (Orchestration) | Complex multi-step microservice transactions (5+ steps), centralized workflow management (Temporal / Step Functions) | Simple 2-step workflows where adding a dedicated orchestrator service is unnecessary | Low to Medium (Central orchestrator manages async step transitions) | High (Decoupled execution with central visibility) | Eventual Consistency (Compensating rollbacks) | Medium |
4. Selection Rules¶
| Requirement | Best Choice | Rationale / Example |
|---|---|---|
| Microservice E-Commerce Order Fulfillment | Saga (Orchestration) | Order Service orchestrates Payment, Inventory, and Shipping microservices |
| Homogeneous Database Shard Commit (XA) | Two-Phase Commit (2PC) | Relational database engine coordinates atomic commit across 2 physical storage shards |
| Avoid Resource Locks Across Microservices | Saga Pattern | Local transactions commit immediately; no cross-service database locks are held |
| Complex 8-Step Business Workflow | Saga (Orchestration) | Orchestrator (Temporal.io) tracks state transitions, timeouts, and compensation steps |
| Simple 2-Step Event Cascade (Order \(\rightarrow\) Email) | Saga (Choreography) | Order service publishes OrderCreated; Email service listens and sends confirmation |
5. Tradeoffs¶
- ACID Isolation vs Eventual Consistency
- Gain (2PC): Transactions are fully isolated; dirty reads and intermediate states are impossible.
- Lose (2PC): Holding blocking locks degrades system throughput and causes deadlocks.
- High Availability vs Synchronous Lock Coordination
- Gain (Saga): Local transactions commit instantly; system remains available even if downstream services crash.
- Lose (Saga): Intermediate dirty states are visible to users before compensation completes.
- Choreography Simplicity vs Event Cascade Chaos
- Gain (Choreography): Loose coupling; no single central orchestrator service to maintain.
- Lose (Choreography): Cyclic event dependencies and difficult post-mortem tracing across 10+ services.
- Orchestration Central Visibility vs Coordinator Dependency
- Gain (Orchestration): Centralized state machine, clear workflow status, and explicit compensation rules.
- Lose (Orchestration): Introduces a dedicated orchestrator service dependency.
- Compensating Transactions Complexity
- Gain (Saga): Reverts state asynchronously without holding long-lived database locks.
- Lose (Saga): Writing idempotent compensating logic (e.g. refunding credit card) is error-prone.
6. Interview Counter Questions¶
- How do the Prepare Phase and Commit Phase work in Two-Phase Commit (2PC)?
- What is the Blocking Coordinator Problem in 2PC and how does Three-Phase Commit (3PC) attempt to fix it?
- What is the difference between Saga Choreography and Saga Orchestration?
- How do Compensating Transactions work in a Saga pattern when step 3 of a 5-step workflow fails?
- Why lacks Isolation (the 'I' in ACID) in the Saga Pattern and how do you mitigate dirty reads?
- How does Temporal.io / AWS Step Functions implement Saga Orchestration?
- What happens if a Compensating Transaction itself fails in a Saga?
- Why is 2PC considered an anti-pattern for microservices across different team boundaries?
- What is an Out-of-Order Execution in Saga Choreography and how do sequence tokens fix it?
- How do semantic locks or pivot transactions mitigate lack of isolation in Sagas?
7. Gold Standard Answers¶
- Prepare Phase: Coordinator asks all nodes "Can you commit?". Nodes acquire locks, write WAL, and reply YES/NO. Commit Phase: If all reply YES, Coordinator sends COMMIT; if any reply NO, Coordinator sends ABORT.
- If the Coordinator crashes after nodes reply YES in Prepare Phase, nodes remain blocked holding locks indefinitely. 3PC adds a
Pre-Commitstate and timeouts to prevent blocking, but fails over unreliable networks. - Choreography: Microservices communicate asynchronously via events without a central controller (Service A publishes
EventA\(\rightarrow\) Service B listens and acts). Orchestration: A central service tells each microservice explicitly which action to execute. - When step 3 fails, the Saga manager catches the error and executes compensating transactions for completed steps in reverse order: Compensate Step 2 \(\rightarrow\) Compensate Step 1 (e.g., Cancel Payment \(\rightarrow\) Release Inventory).
- Sagas commit local transactions immediately, exposing intermediate states. Mitigate using: (1) Semantic Locks (flag record as
PENDING_APPROVAL), (2) Commutative updates, (3) Reread-verify checks before final actions. - Temporal maintains an event-sourced durable state machine. It executes workflow code as a sequence of deterministic steps, automatically tracking retries, timeouts, and executing compensation functions on failure.
- Compensating transactions must be designed to be idempotent and retried infinitely until success. If retry limits are exceeded, raise P1 alerts to a Dead-Letter Queue (DLQ) for manual operational intervention.
- 2PC couples database schemas and execution threads across service boundaries over the network. If Team B's service slows down, Team A's database locks remain open, breaking service autonomy.
- Out-of-order events occur when Event 3 arrives before Event 2. Inject monotonically increasing sequence tokens or version IDs into event payloads so consumers reject or queue out-of-order events.
- A Pivot Transaction is the point-of-no-return in a Saga. Steps before the pivot must have compensations. Once the pivot transaction commits, subsequent steps cannot fail and must execute to completion.
8. Common Mistakes¶
- Using 2PC across independent microservices owned by different teams, creating cascading lock outages.
- Assuming Saga Pattern provides ACID isolation out-of-the-box without handling dirty reads via pending status flags.
- Writing non-idempotent Compensating Transactions (e.g., executing duplicate refunds when retrying compensation).
- Choosing Saga Choreography for complex 10+ step workflows, resulting in un-debuggable "spaghetti event" architectures.
- Forgetting to handle cases where a compensating transaction fails permanently.
9. Keywords¶
Two-Phase Commit (2PC), Three-Phase Commit (3PC), Saga Pattern, Choreography, Orchestration, Compensating Transaction, Pivot Transaction, Semantic Lock, Temporal.io, AWS Step Functions, XA Transactions, Prepare Phase, Commit Phase, Dirty Reads.
10. Cheat Sheet¶
- 2PC (Two-Phase Commit): Synchronous 2-phase lock coordination (Prepare + Commit). Guarantees ACID isolation, but blocking locks destroy availability & throughput. (Use for DB engine internal shards only).
- Saga Pattern: Sequence of local ACID transactions with async Compensating Transactions on failure. High availability & loose coupling, but eventual consistency. (Use for Microservices).
- Choreography vs Orchestration: Choreography = Simple event-driven cascades (2-4 steps); Orchestration = Centralized state machine manager (5+ steps e.g. Temporal.io).
- Compensating Rule: All compensating transactions MUST be Idempotent and retried until success.
- Isolation Fix: Lack of Saga isolation \(\rightarrow\) use Semantic Locks (
status = PENDING_PAYMENT) to prevent dirty reads. - Pivot Transaction: The point of no return in a Saga. Once the pivot commits, downstream steps CANNOT fail.