On this page
Before you start
This lesson uses ideas from these earlier lessons. Read them first if any idea is new to you.
01Why interviewers ask this
The interviewer says: "A transfer takes money from an account in one database and adds it to an account in another. It must not lose money or create money. What if a server dies in the middle? Why not one big transaction?"
A weak answer says "use a distributed transaction" or "use a saga" and stops. A strong answer says what each tool holds while it waits, what a dead server leaves behind, and how an undo works. It also says when no undo exists, and picks by the data and the lock time.
This is an SDE-3 question. It builds on lessons 92 and 95 and goes further.
02The idea in plain words
A wedding planner phones three vendors with one question: "Can you come on Sunday?" Each says "Yes, I keep Sunday free for you." So no vendor takes other work for Sunday. Then the planner calls again: "Confirmed." If the planner disappears after the yes answers, the vendors wait. They cannot take other work, and they cannot be sure whether to come.
Two-phase commit, step by step
Two-phase commit is this call, between a coordinator and the participants, the databases that take part (lesson 95).
- The coordinator asks every participant to prepare.
- Each participant does the work and locks its rows. It writes a prepare record to its log, which is a promise to commit if told. Then it votes yes or no.
- If all vote yes, the coordinator writes "commit" in its own log. This is the decision. Any no, or a timeout, gives "abort".
- The coordinator tells everyone. Each participant finishes and releases its locks.
Look at each failure point.
| Failure | What happens |
|---|---|
| A participant dies before it votes | The coordinator times out and aborts. Safe. |
| A participant dies after voting yes | On restart it reads its prepare record and asks for the decision. |
| The coordinator dies after the prepare, before telling anyone | Participants that voted yes are in doubt: they promised to follow the decision, and do not know it. |
An in-doubt participant cannot commit alone, because the decision may be abort. It cannot abort alone, because the coordinator may have decided commit and told others. It can ask the other participants. If one of them knows the decision, or never voted yes, the question is settled. If all of them are in doubt, all wait and hold their locks. Database manuals warn about this. A prepared transaction keeps its locks (PostgreSQL). In-doubt data may be locked for reads and writes until it is resolved (Oracle).
Repair: groups of copies
The weak point is one machine. So make the coordinator and each participant a group of copies that agree by consensus (lesson 80). Each prepare and commit record is saved by a majority. If the coordinator's leader dies, another copy has the log and finishes the decision. A dead machine no longer blocks everyone. This works only when every participant is a database you run with this support. A payment gateway or a bank cannot prepare.
Sagas in depth
Lesson 95 gave the saga: steps with compensations. Four more points.
- Order the steps. First come steps that can be undone (compensable). Then one pivot, the point of no return. After it, every step is retryable: it is idempotent and is retried until it works. After the pivot you never undo, you go forward.
- A compensation can fail too. Retry it until it works, with the same key. Raise an alarm after a limit. The saga stays in a "compensating" state.
- Who runs it. With orchestration, one controller holds the plan. It keeps the saga state in a row that says which step the saga is on. A controller that crashes reads the row and continues. With choreography, services react to events, so no row shows the whole saga. A stuck compensation is then hard to see, and orchestration is easier to watch for long sagas.
- Guard the middle. Other users see half-done work. Show a pending state. Use a semantic lock, a flag that says "a saga is working on this". Use updates that can be applied in any order, such as "subtract 500 if the balance is at least 500".
Outbox with an idempotent consumer
Delivery may repeat, but the effect must happen once. Each step does one local transaction: change the data and write an outbox row (lesson 92). A relay sends the row. It can poll the table, or read the database log with change data capture (lesson 92). The next service saves the message ID with a unique constraint in the same transaction as its effect (lesson 89). A repeat finds the ID and does nothing. This works when the effect is in the same database as the ID table. For an outside effect, such as an email, send the ID as the provider's key if it accepts one.
Choosing
| Tool | Use when | Locks across steps | Undo |
|---|---|---|---|
| One database transaction | All the data is in one database | None | Rollback |
| Two-phase commit | You run every participant, and the lock time is short | From prepare to commit | Abort |
| Saga | Several services or outside providers | None between steps | Compensation, until the pivot |
| Outbox and idempotent consumer | One service changes data and must tell another | None | None: forward only |
Want to check your understanding? Try explaining this idea in your own words. You can continue reading first, or ask the AI tutor a question. Sign up free to ask the tutor
03Pause and predict
Pause. Guess first.
A coordinator crashes after all participants voted yes and before it sent any answer. Can a participant commit alone? Can it abort alone?
Write your guess before you read on. The answer is in the worked example.
04Worked example
PayEasy moves Rs 500 from Asha (database 1) to Ravi (database 2).
Assumptions (made up to teach with): 2,000 transfers per second at peak. A message trip takes 0.5 ms. A write saved by a majority takes 2 ms. A merchant account gets 100 transfers per second. A single database holds its locks for about 1 ms. 10,000,000 transfers a day. 0.5% fail at the credit step.
Step 1: two-phase commit over copies. Timeline in ms: 0 prepare is sent. At 0.5 the locks are taken and the prepare record is saved by a majority, done at 2.5. The vote arrives at 3.0. The decision is saved, done at 5.0. Asha hears "done" at 5.5. The commit reaches the participants at 5.5 and is saved at 7.5. Locks are held from 0.5 to 7.5: 7.0 ms. A single database holds them about 1 ms.
Step 2: a hot row. One row can take 1,000 / 7.0 = 143 transfers per second. The merchant needs 100, so the row is 70% busy. A local saga step holds the row 2 ms: 1,000 / 2 = 500 per second, and the row is 20% busy.
Step 3: a dead coordinator. A participant is in doubt from its vote (2.5) until the decision reaches it (5.5): 3 ms. In doubt at any time: 2,000 x 0.003 = 6 transfers, 12 rows locked. This answers the predict box: neither. With one coordinator machine down for 30 seconds, a locked merchant row blocks 100 x 30 = 3,000 transfers. With a group, a new leader takes about 1 second (assumption; lesson 80 has timeouts of 150 to 300 ms): 100 transfers wait.
Step 4: the saga. Steps: debit Asha (compensable), credit Ravi (the pivot), write the statement entry (retryable). The credit fails for 0.5% of 10,000,000 = 50,000 transfers a day. Each runs the compensation, which credits Asha back. Assumption: a compensation call fails 2% of the time. Expected calls: 50,000 / (1 - 0.02) = 51,020, so 1,020 extra. Five failures in a row for one compensation: 0.02 to the power 5 = 3.2 in 1,000,000,000.
Step 5: the middle. The credit comes 200 ms after the debit (assumption). Money in flight: 2,000 x 0.2 = 400 transfers x Rs 500 = Rs 200,000 (2 lakh). Show state DEBITED, and count it as "in transit" in reports. Asha has Rs 600 and starts two transfers of Rs 500. If both read 600, the balance goes to -400. With "debit 500 only if the balance is at least 500", the second fails.
Step 6: repeats. Assumption: the relay crashes 3 times a day (lesson 92), and each crash sends one transfer twice. Without a saved transfer ID: 3 x Rs 500 = Rs 1,500 of new money each day. With the ID: Rs 0.
Step 7: choose. Between two of our own databases, two-phase commit works if the lock time is acceptable (7.0 ms). A saga works if a pending state is acceptable. To an outside bank: a saga, because the bank cannot prepare. Order placed, then an email: an outbox.
What companies wrote
- Google (the Spanner database paper, OSDI 2012): each participant is a group of copies that agree by Paxos, a consensus method like Raft. The group leaders run two-phase commit, and the paper says this eases the availability problem. It reports that 50 participants is reasonable and that latency rises noticeably at 100 (the paper's figures). Link: https://research.google.com/archive/spanner-osdi2012.pdf (opens in a new tab)
- Netflix wrote in October 2026 (post listed 14 Oct 2026) that its workflow engine keeps the state of each workflow in a durable store. So long work survives failures. An older engine design changed state in several places, and competing updates could leave a workflow inconsistent. Link: https://netflixtechblog.com/netflix-conductor-the-next-chapter-41ad21067649 (opens in a new tab)
05Trade-offs
Two-phase commit over copies solves all-or-nothing across databases that you run, without a single machine that can block everyone. It costs lock time (7.0 ms against 1 ms) and a majority wait at every step. A saga solves outside providers and long steps. It costs compensations and a visible middle (Rs 200,000 in flight). I would change to a saga when a participant cannot prepare, or when a hot row cannot give 7 ms of lock time.
06Common misconceptions
"A participant that voted yes can time out and abort by itself." The coordinator may have decided commit and told others. In step 3, neither choice is safe alone.
"Putting the coordinator in a group removes the cost of two-phase commit." It removes the blocking by one dead machine. Locks, majority waits and the participant count stay.
"A saga that fails just runs the undo steps, and they always work." A compensation can fail. In step 4, 1,020 calls a day were retries. After the pivot there is no undo at all.
07How to say it in the interview
Say it like this
Between databases I run, I accept two-phase commit only if every part is a group of copies and the lock time is short. For outside providers I use a saga with a pivot, retried compensations and an outbox with an idempotent consumer.
08Check your understanding
- What does "in doubt" mean in two-phase commit, and why can the participant not decide alone? What is the pivot in a saga?
- Two-phase commit holds a row for 8 ms, and a local saga step holds it for 2 ms. A merchant row gets 100 transfers per second. (a) What is the highest rate for each? (b) There are 4,000,000 transfers a day and 0.5% need a compensation, which fails 5% of the time and is retried until it works. How many calls a day?
- A team wants one two-phase commit across its own database and a card provider's API. What do you say?
09Answers
Show the answers
- A participant is in doubt when it has voted yes and does not know the decision. The decision may be commit or abort, and others may already have acted on it. The pivot is the step after which the saga is never undone, and all later steps are retried until they work.
- (a) 1,000 / 8 = 125 per second for two-phase commit. 1,000 / 2 = 500 per second for the saga. (b) 0.5% x 4,000,000 = 20,000 compensations. Expected calls: 20,000 / (1 - 0.05) = 21,053, so 1,053 retries.
- The provider cannot prepare or hold locks for you. Use a saga: charge with an idempotency key, record the intent in your database first, and refund as the compensation. Use an outbox so the charge request is not lost.
10Summary card: distributed transactions in depth
One-page summary
- Two-phase commit: prepare (lock, log a promise, vote), then commit or abort. A participant that voted yes and hears nothing is in doubt: it holds locks and cannot decide alone.
- A dead coordinator blocks everyone. The repair: the coordinator and each participant are groups of copies agreeing by consensus. Cost: a majority wait at each step, and locks held for 7.0 ms instead of 1 ms in the example.
- Sagas: compensable steps, then a pivot, then retryable steps. A compensation can fail: retry it until it works. Keep the saga state in a row. Guard the middle with a pending state, a semantic lock and updates that work in any order.
- Outbox plus idempotent consumer: delivery may repeat, the effect happens once.
- Choose by who owns the data, how long locks may be held and whether an undo exists.
- Trap: letting a yes-voter abort alone.
11Sources
- Corbett and others, "Spanner", OSDI 2012 (participant groups are Paxos groups; their leaders run two-phase commit; each transaction manager's state is stored in its group; two-phase commit over Paxos eases the availability problems; 50 participants is reasonable and latency rises at 100): https://research.google.com/archive/spanner-osdi2012.pdf (opens in a new tab) (checked 26 Oct 2026).
- PostgreSQL manual, PREPARE TRANSACTION (for an outside transaction manager; the transaction keeps its locks; leaving it prepared for long is unwise): https://www.postgresql.org/docs/current/sql-prepare-transaction.html (opens in a new tab) (checked 26 Oct 2026). Oracle Database, distributed transactions (in-doubt transactions; data locked for reads and writes until resolved): https://docs.oracle.com/en/database/oracle/oracle-database/19/admin/distributed-transactions-concepts.html (opens in a new tab) (checked 26 Oct 2026).
- Garcia-Molina and Salem, "Sagas", ACM SIGMOD 1987 (a long transaction as steps with compensating transactions): https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf (opens in a new tab) (checked 26 Oct 2026). Microsoft Learn, Saga pattern (compensable, pivot and retryable steps; choreography and orchestration; compensations can fail; semantic lock and commutative updates; page dated 25 Feb 2025): https://learn.microsoft.com/en-us/azure/architecture/patterns/saga (opens in a new tab) (checked 26 Oct 2026). Microsoft Learn, Idempotent Consumer pattern (the key and the effect in one transaction; a unique constraint): https://learn.microsoft.com/en-us/azure/architecture/patterns/idempotent-consumer (opens in a new tab) (checked 26 Oct 2026).
- Debezium, Outbox Event Router (change data capture reads the outbox table; consumers use the event id to remove repeats): https://debezium.io/documentation/reference/stable/transformations/outbox-event-router.html (opens in a new tab) (checked 26 Oct 2026).
- Netflix: link in the box above (checked 26 Oct 2026; read from the company's blog feed, because its page refused automated access).
- All rates, times, probabilities and money in the worked example are assumptions made for teaching. The majority-write timeline is a simplified model, not a measurement.
Try what you just learned
Put this idea into practice with a short exercise or a relevant tool. Free to try. No sign-up needed.
More practice. This needs a free account.
- Quick Round: saga or two-phase commit for a booking
- Quick Round: outbox or dual write for orders
- Quick Round: 1,200 users have extra wallet money
- Quick Round: cashback must never repeat and never go missing
- Incident investigations: the same work was done twice
- Trade-off page: saga or two-phase commit
- Trade-off page: outbox, dual write or change data capture
- Practical problem: design a payment system
- Practical problem: design a ticket booking system
- Classic problem: hotel booking
What to learn next
Continue learning with the lessons that build on this one.
- How a log-based queue stores data: segments, offsets, retention, compaction, replication
- Cell-based architecture: limiting the blast radius
- Batch processing and data warehouses: files, columns and star schemas
Practise this idea
Have a question about this lesson?
Ask the AI tutor to explain a difficult idea, walk through an example or check your understanding. It uses the lesson to help you work through the topic.
A free account includes 10 AI tutor questions a day. The lesson remains free to read without an account.
All lessons in Module 23: Big systems in depth
Prefer another topic? Browse all 169 lessons.