CONCEPT SHEET · Concepts

Distributed Transactions and Sagas

One-liner: Across services you either lock everyone with 2PC or chain local transactions with compensations (saga); the outbox pattern makes the events reliable.

ArticleConcepts© Arthur Bernier Jr536 words2 code blocks

Say this#

How it works#

2PC:

TEXT
coordinator -> PREPARE -> [A] [B] [C]   each writes to log, holds locks, votes YES/NOcoordinator -> COMMIT  -> [A] [B] [C]   if all YES; else ABORT

Saga (orchestration, e.g. order flow):

  1. Orchestrator: ReserveInventory → ChargePayment → CreateShipment.
  2. Each step is a local ACID transaction in its own service.
  3. If ChargePayment fails: run ReleaseInventory (compensation) in reverse order.
  4. Orchestrator state persisted so it survives crashes (Temporal workflow history).

Outbox:

TEXT
BEGIN; INSERT order; INSERT outbox(event); COMMIT;relay/CDC -> Kafka topic -> consumers (idempotent, dedupe on event_id)

Trade-offs#

ChoiceProCon
2PCAtomic across resources, simple mental modelBlocking on coordinator failure, locks held across network, latency, poor availability
Saga choreographyLoose coupling, no central componentHard to see the flow; cyclic event dependencies; debugging
Saga orchestrationExplicit flow, easy to reason about and retryOrchestrator is a component to run HA; some coupling
Outbox + CDCExactly-once-ish publication, no dual writeExtra table, relay to operate, at-least-once to consumers
Just use one DBReal ACIDDoesn't fit service-per-DB boundaries

Numbers#

  • 2PC adds at least 2 round trips plus 2 fsyncs per participant before commit; cross-region this is 100+ ms.
  • Sagas are eventually consistent: the intermediate state is visible for the saga's duration (ms to hours).
  • Spanner/CockroachDB use 2PC over Paxos/Raft groups internally; the lock hold time is bounded by consensus latency, not a flaky coordinator.

In the interview#

See also