Transactions and coordination
Explain consensus, logical ordering, leases and fencing under stated failure and timing assumptions.
THE IDEA
Transactions and coordination
Two-phase commit makes several participants agree on one outcome: first everyone votes in a prepare phase, then the coordinator announces commit only if all voted yes, otherwise abort. It has a known weakness: if the coordinator fails after the prepare phase, participants that voted yes are stuck, holding locks and unable to decide alone, until recovery. Consensus (Raft) and atomic commit are related but different problems: replicating a log does not by itself make changes in several services atomic.
Predict first. Does running Raft automatically give an application a correct cross-service transaction?
Chapter context
Coordination lets multiple processes agree on selected shared decisions even though messages can be delayed or lost and participants can stop. Agreement is achieved by a protocol, not by adding a shared timestamp or an informal majority rule.
TRY IT YOURSELF
Part 1. Do it hands-on
Decide outcomes and blocking by hand, then simulate two-phase commit.
- To do: Two-phase commit: three participants vote yes, yes, no in the prepare phase. Outcome? Type commit or abort
- To do: All three vote yes. Outcome?
- To do: All three voted yes and then the coordinator crashes before telling anyone the decision. Participants stuck holding locks, not knowing the outcome?
- To do: Does running Raft automatically give an application a correct cross-service transaction? Type yes or no
Part 2. Do it in code
- two_phase_commit(votes, coordinator_crashes_after_prepare=False): votes is a list of "yes"/"no". Phase 1: every participant votes. If the coordinator crashes after the prepare phase and before sending the decision, return {"decision": "unknown", "states": each participant that voted yes is "prepared" (blocked), each that voted no is "aborted"}. Otherwise the coordinator decides "commit" only if all votes are yes, else "abort", and sends it: states are "committed" or "aborted".
- blocked(result): number of participants in the "prepared" state.
- can_unblock(result, coordinator_recovers): True if no participant is blocked, or the coordinator comes back and can tell them the outcome. (Without it, prepared participants must wait.)
- raft_gives_transaction(): always False — a replicated log orders decisions but does not make changes in several services atomic.
Stuck, or something not working? You can come back to it any time.
CHECK YOUR UNDERSTANDING
Does running Raft automatically give an application a correct cross-service transaction?
Chapter reference: math, worked example & code
This section belongs to the whole chapter, so it is the same on every lesson in it and may cover a different lesson's topic. The code for the experiment you just ran is inside the experiment itself.
Math and notation
For a fixed n-member majority group, quorum size is . A 2f+1-member group can lose f members while retaining a majority, provided the remaining participants can communicate and the protocol's other assumptions hold. Fencing requires monotonically ordered tokens and enforcement at the resource.
Worked example
Five members require three votes, allowing two unavailable members while a communicating majority remains. Separately, a resource has already accepted token 8 from a new owner. An old owner's delayed operation bearing token 7 must be rejected, regardless of whether the old process still believes it owns the lease.
Reference code
The following example uses the Python standard library and does not call a remote service.
members=5
quorum=members//2+1
assert quorum == 3 and members-quorum == 2
highest=8
def accept(token):
global highest
if token < highest: return False
highest=token
return True
assert not accept(7)
assert accept(8)
assert accept(9)
Python examples are provided for study and local execution; this page does not execute Python.
Common mistakes
A timeout cannot establish a remote process's state. Quorums require full protocol rules. Fencing is ineffective if the resource accepts stale tokens or an attacker can invent authorized tokens.