Distributed Systems Theory
Distributed Transactions
- 2PC has a coordinator ask every participant to prepare (lock resources, promise to commit), then tell them all to commit only if everyone agreed
- 2PC's fatal weakness: if the coordinator crashes after some participants prepare but before it sends commit/abort, those participants block holding locks indefinitely
- Sagas replace one distributed transaction with a sequence of local transactions, each with a compensating action to undo it if a later step fails
- Sagas give up isolation — intermediate states are visible to other transactions — in exchange for not blocking on a coordinator
- Idempotent operations (Exactly Once And Idempotency) are what make retrying a saga step (or a crashed 2PC participant) safe
A single database gives you transactions for free. The moment a change spans two databases, two services, or two shards, you have to build that atomicity guarantee back yourself — and the two dominant answers, 2PC and sagas, sit at opposite ends of a consistency/availability tradeoff.
Two-phase commit
Every participant that votes yes must hold its locks and survive a crash with that promise durably logged — it cannot unilaterally decide to commit or abort afterward, only the coordinator's final word matters. That is exactly the problem: if the coordinator dies after collecting votes but before broadcasting the decision, every prepared participant is stuck holding locks, unable to proceed, waiting for a coordinator that may never come back. This is why 2PC is called a blocking protocol.
Sagas: local transactions plus compensation
interface SagaStep {
void execute();
void compensate(); // undo, called if a LATER step fails
}
void runSaga(List<SagaStep> steps) {
Deque<SagaStep> completed = new ArrayDeque<>();
try {
for (SagaStep step : steps) {
step.execute();
completed.push(step);
}
} catch (Exception e) {
while (!completed.isEmpty()) {
completed.pop().compensate(); // unwind in reverse order
}
throw new SagaFailedException(e);
}
}A typical order-placement saga: reserve inventory, charge payment, schedule shipping. If shipping scheduling fails, the saga runs compensations in reverse — refund the payment, release the inventory reservation — rather than one giant lock held across all three services for the whole duration.
| Two-phase commit | Saga | |
|---|---|---|
| Atomicity | True all-or-nothing, enforced by locks | Eventual — a failure partway is undone, not prevented |
| Isolation | Full — nothing sees intermediate state | None — other transactions can see a saga's partial progress |
| Failure mode | Blocks: prepared participants wait forever for the coordinator | Never blocks — always makes forward or compensating progress |
| Fits | A single trusted coordinator, low-latency network, few participants | Microservices, long-running or cross-organization workflows |