Articles

Two-Phase Commit vs. Saga Pattern Explained

Two-phase commit locks resources until every node agrees to a transaction; the saga pattern trades that guarantee for availability using compensating steps.

The Lycoris Team The Lycoris Team · · 5 min read
Abstract illustration representing database structures

Two-phase commit and the saga pattern both answer the same question — how do you keep a transaction consistent when it spans multiple databases or services — but they answer it in opposite ways. Two-phase commit keeps every participant locked and waiting until all of them agree to commit, preserving atomicity at the cost of availability during that wait. The saga pattern lets each step commit immediately and independently, preserving availability and accepting that a failure partway through has to be cleaned up afterward rather than prevented beforehand. Which one fits depends entirely on how much you can afford to lock, and for how long.

Two-phase commit: agree first, commit second

Two-phase commit (2PC) coordinates a distributed transaction through a single coordinator and multiple participants, in two strict phases:

  1. Prepare phase — the coordinator asks every participant “can you commit this?” Each participant does whatever work is needed to guarantee it can commit — validating constraints, writing to a durable log — and locks the relevant resources, then replies yes or no. No actual commit happens yet.
  2. Commit phase — if every participant said yes, the coordinator tells them all to commit for real. If even one said no, the coordinator tells everyone to roll back instead.

This gives genuine atomicity: either every participant commits, or none of them do, with no in-between state ever visible to the outside world. The cost is that every resource involved stays locked for the entire round trip — including a full network round trip to every participant — and if the coordinator crashes after participants have said yes but before it sends the final commit, those participants are stuck holding locks indefinitely, unable to safely commit or roll back on their own. That blocking failure mode is 2PC’s best-known weakness, and it’s why the protocol scales poorly across unreliable networks or a large number of participants.

The saga pattern: commit now, compensate later

The saga pattern takes the opposite approach: break the transaction into a sequence of local, independent steps, each of which commits on its own as soon as it succeeds — no locking, no waiting for the other steps to agree. If a later step fails, the saga doesn’t roll back in the database sense; instead, it runs compensating actions that semantically undo the effects of the steps that already committed. Canceling a reservation instead of rolling back a “book seat” transaction, refunding a charge instead of rolling back a “charge card” transaction — the compensation is business logic you write, not a mechanism the database provides for free.

Sagas are typically coordinated one of two ways: choreography, where each service publishes an event when it finishes and the next service reacts to it (often over a message queue or a system like the ones compared in Kafka vs RabbitMQ), or orchestration, where a central coordinator explicitly tells each service what step to run next and calls the compensating steps itself if something fails.

Side by side

Two-phase commitSaga pattern
AtomicityTrue — all or nothing, alwaysApproximate — undone via compensation after the fact
LockingResources locked until all participants agreeNo cross-service locking
Availability during the operationReduced — participants blockPreserved — each step commits independently
Failure recoveryCoordinator retries or aborts before commitCompensating actions run after partial commits
Coordinator crashCan leave participants blocked indefinitelyNo blocking; recovery is just resuming or compensating
Best fitTightly coupled systems, short transactions, few participantsLoosely coupled microservices, longer-running processes

Why sagas dominate microservice architectures

In a microservices architecture, 2PC’s requirement that every participant lock resources and stay reachable for the duration of the transaction runs directly against the reason most teams adopt microservices in the first place: independent deployability and independent availability. A coordinator that needs a synchronous handshake with a dozen services before anything commits reintroduces the tight coupling microservices were meant to remove, and the CAP theorem tradeoff becomes unavoidable — 2PC leans hard toward consistency at the direct expense of availability. Sagas accept a weaker guarantee (the system passes through visibly inconsistent intermediate states while a saga is in flight) in exchange for services that never have to block on each other’s locks, which is why sagas — not 2PC — are the default answer for coordinating a checkout flow, an order fulfillment pipeline, or any multi-step business process spread across services.

What each approach demands of your code

2PC pushes the complexity into infrastructure: participants need to support a prepare/commit protocol, and the coordinator needs durable logging to recover safely from crashes, but application code mostly just issues a transaction and waits for the result. Sagas push the complexity in the opposite direction, into application logic: every step needs a corresponding compensating action, and that compensation has to be correct even if it runs long after the original step, possibly interleaved with other operations. Idempotency becomes non-negotiable — see our piece on idempotency — because retries, timeouts, and out-of-order delivery mean a step or its compensation might run more than once, and sagas typically lean on event sourcing or an explicit state machine to track exactly which steps have committed so recovery logic knows what still needs compensating.

Choosing between them

Reach for two-phase commit when the number of participants is small, they’re all reachable on a reliable network (often within the same data center or even the same database cluster), and the transaction is short-lived enough that blocking for its duration is tolerable — some databases use 2PC internally for exactly this reason. Reach for the saga pattern when the transaction spans services owned by different teams, might take seconds to minutes to complete end to end, or needs to stay available even if one participant is temporarily down. Most systems built as microservices land on sagas by default, not because sagas are strictly better, but because the environment they run in makes 2PC’s blocking behavior a worse tradeoff than living with eventual, compensatable consistency.

The takeaway

Two-phase commit and the saga pattern sit at opposite ends of the same tradeoff: strict atomicity through blocking locks, versus availability through independent commits and after-the-fact compensation. 2PC fits small, tightly coupled, short-lived transactions where blocking briefly is acceptable; sagas fit the long-running, loosely coupled, service-spanning transactions that define most microservice architectures. Neither eliminates complexity — 2PC concentrates it in infrastructure and coordination, while sagas concentrate it in compensating business logic — so the right choice comes down to which kind of complexity your system is better positioned to absorb.

Chisato Chisato · · 4 min read

Byzantine Fault Tolerance Explained

Byzantine fault tolerance lets a distributed system keep working correctly even when some nodes fail arbitrarily or actively lie, not just crash cleanly.

#Distributed Systems #Computer Science #Databases
Chisato Chisato · · 5 min read

Raft vs Paxos: Consensus Algorithms Compared

Raft and Paxos both let a distributed cluster agree on a value despite failures — Raft trades some flexibility for a design built to be understood.

#Distributed Systems #Computer Science #Databases
The Lycoris Team The Lycoris Team · · 4 min read

Read-Your-Writes Consistency Explained

Read-your-writes consistency guarantees a client sees its own writes immediately, even when other clients might not yet. How it's implemented.

#Databases #Distributed Systems #Computer Science