Skip to lesson
‹

Courses / System Design Interview / Chapter 8

Module 2 · Building Blocks · Chapter 8 of 39

Consensus, Leader Election and Coordination

18 sections · ~32 min✓ Fact-checked

Builds on Abstractions That Hide the Network, Availability, Reliability, Scalability and Latency and Databases: Replication, Partitioning and Choosing a Store. Next up: Designing a Key-Value Store.

Part 1 · The Problem: Exactly One in Charge

Some jobs need exactly one owner

It is 10:00:04 on a tatkal morning, and a railway booking site is taking 20,000 booking requests a second. The primary database that holds coach B4's seats freezes for eight seconds in a garbage-collection pause. Its standby hears no heartbeat for five seconds and promotes itself. Then the old primary wakes up, unaware that any time has passed, and keeps selling. For the next half minute two primaries accept bookings, and seat 23 in coach B4 is sold to Asha on one and to Vikram on the other. Two passengers will board with tickets for one berth, and someone will untangle it by hand.

This chapter follows that booking site. Many of its parts work only when exactly one machine is in charge, and each breaks in its own way when two act at once:

JobIf two machines act at once
Writes for coach B4's seatsBoth sell seat 23, and the copies diverge
The chart job, which gives freed berths to waitlisted passengersTwo passengers get the same berth
The partition mapTwo routers send one booking to different machines

Every row needs the same guarantee: at most one owner at a time, even while machines crash, freeze and lose touch.

The obvious design is one coordinator that decides for everyone: simple, fast, and a single point of failure. The real question is how to add a spare without ever creating two owners.

Why a standby on a timer fails

The natural fix is a spare. A primary sends a heartbeat every second, and a standby promotes itself after 5 seconds of silence. It is like a night watchman who decides his partner has gone home because the phone line went quiet. That works when the primary crashes, and fails when it is only slow or cut off.

Two primaries in under ten seconds
  1. 1The link between the two machines dropsBoth can still reach booking servers and their disks
  2. 2The standby hears nothing for 5 secondsFrom where it sits, a dead primary and a cut cable look the same
  3. 3The standby promotes itselfNobody tells the old primary, so two machines accept writes
  4. 4Each sells seats the other never seesThe copies diverge until someone merges them by hand

This is split brain: two nodes each believe they lead and accept writes the other never sees. It needs no network fault at all; the tatkal outage was a pause, and to a paused process no time has passed.

Tuning the timer does not save it. A shorter timeout promotes the standby during ordinary pauses; a longer one leaves the site without writes for longer after a real crash. As the abstractions chapter put it, a timeout cannot tell a slow node from a dead one.

The cure has two halves: let a majority of a small group decide who leads, so two sides of a split cannot both win, and number every leadership, so an old leader that wakes up late can be refused. The next part starts with majorities.

Part 2 · Majorities and Consensus

Majorities: why 3 and 5

A majority works like a committee that needs more than half its members to pass anything: a room split in two cannot have more than half on both sides. Run a small group of nodes and let a decision stand only when a majority, also called a quorum, agrees. Any two majorities of the same group share at least one node, and that shared node will not agree to two conflicting things.

How many nodes? Each size survives a different number of failures:

NodesMajorityFailures survived
110
220
321
431
532
642
743

Survival steps up only at odd sizes. This is the 2f + 1 rule: 2f + 1 nodes survive f failures.

An even count buys nothing: 4 nodes need 3 for a majority, so they survive one failure, like 3, while adding one more machine that can fail. Five survive two, which matters because one node is often down on purpose for an upgrade, and you still want to survive a crash during it.

Bigger groups cost more: a group of 7 waits for 3 followers on every write instead of 2. Most groups run 3 or 5 nodes.

Use three zones

Place 3 nodes in 3 zones, or 5 as 2 + 2 + 1, and losing any zone leaves a majority. With only two zones, one zone always holds the majority, and losing that zone stops every write.

Consensus, logs and terms

A majority can vote, but on what? Consensus is getting a group of nodes to agree on values and never change their minds, even while some crash. Picture three clerks keeping copies of one register: if each writes the same lines in the same order, every copy reads the same.

In practice the nodes agree on a log, an ordered list of commands such as "sell B4-23 to Asha". Each node applies the log in order to its own copy of the data, so all copies end in the same state. This is called state machine replication.

The best-known protocol is Raft, built around one leader; the older Paxos family solves the same problem, and its common form also uses a leader. In Raft each node is a follower, a candidate or the leader. Time is cut into numbered terms, like numbered editions of a newspaper. Each term starts with an election and has at most one leader. Every message carries the sender's term, and two rules follow:

  • A node that sees a higher term adopts it and becomes a follower at once, even if it was leading.
  • A request stamped with a lower term is rejected, and the reply names the current term.

These rules are the numbering half of the cure. An old leader is refused by its term number, without anyone telling it that it was replaced. The next page shows how a term gets its leader.

Electing a leader

Terms need leaders, and leaders are chosen by vote. The leader sends a heartbeat to every follower, say every 100 ms. Each follower runs an election timeout, picked at random from a range such as 1 to 2 seconds and reset by every heartbeat. When the timer runs out, the follower assumes the leader is gone and calls an election.

One election, step by step
  1. 1A follower's timer runs outIt becomes a candidate, moves to the next term and votes for itself
  2. 2It asks the others for votesWith the new term and the position of its last log entry
  3. 3Each node votes at most once per termFirst come, first served, never for a candidate whose log is behind its own
  4. 4A majority of votes makes it leader2 of 3, or 3 of 5; heartbeats start at once
  5. 5Votes split: wait and retryRandom timeouts make a second split unlikely

Two rules make the result safe. One vote per term means no term has two leaders: two winners would need two majorities, which share a node that voted once. Refusing a candidate with an older log means the winner holds every committed entry: that entry sits on a majority, the winner needed a majority of votes, and the two share a node that would have refused it.

The timeout sets the price of a failover: writes pause for about one timeout plus a vote, a second or two. Set it below a healthy leader's worst pause, such as a 2-second garbage collection, and followers call needless elections; set it at 10 seconds and every crash costs 10 seconds of writes. Pick the timeout above the worst normal pause, and accept the failover time that follows.

Committing on a majority

Once elected, how does a leader make a write stick? The leader handles every write. Asha's booking arrives, and the leader appends "sell B4-23 to Asha" to its log as entry 57 in term 4, then sends it to the followers. Each follower checks that its log matches the leader's up to entry 56, saves the entry to disk and replies.

Once a majority, counting the leader, has the entry on disk, it is committed: the leader applies it to the seat table, tells Asha her seat is booked, and tells the followers to apply it in its next message. A committed entry is never lost or changed, because every future leader needs a majority of votes, and that majority includes a node holding the entry.

The latency follows from the majority rule. With 3 nodes a write waits for the faster of 2 followers; with 5, for the second-fastest of 4. In one region that is a network round trip plus a disk flush, a few milliseconds, and one slow follower changes nothing.

Not every write commits. The leader repairs followers by resending from the last entry they agree on, and it overwrites entries an old leader never committed. So a write that timed out may or may not have committed, and the client cannot tell which; retries need the idempotency keys from the abstractions chapter. The next page puts these pieces together in a failover.

A failover, step by step

Here is the tatkal outage again, on a three-node consensus group. Node A leads term 4, commits Asha's booking, then freezes. B and C must carry on, and A must sell nothing when it wakes.

Predict before you watch: after B wins term 5, A wakes still believing it leads, and a booking server asks it for seat B4-24, which B has already sold. What happens to A's write?
  • It never commits. C is in term 5 and refuses an append stamped with term 4, so A steps down and tells the server to ask B.
Animated sceneA frozen leader, and its old term refused0:28

Watch for the term numbers: A leads term 4, and a sale counts once 2 of 3 store it

Read it as steps

Node A freezes, B wins term 5 by majority vote, and A's late sale of seat B4-24 bounces off the higher term.

Nobody told A it had been replaced. The higher term did the work: C refused an append stamped with term 4, A stepped down, and B's log will overwrite A's uncommitted entry. The booking server got an error instead of a false "booked", and seat B4-24 has one owner. The double sale from the opening cannot happen, because a stale leader cannot gather a majority.

What a network split does

A frozen leader is one failure; a cut network is the other. What each side of a split can do depends only on whether it holds a majority. Take a 5-node group spread 2 + 2 + 1 over three zones:

SplitWhat happens
The leader is cut off with one other node (2 against 3)The 2 cannot commit, so writes sent there time out; the 3 elect a new leader and carry on
The leader is on the majority side (3 against 2)Nothing visible changes; the cut-off followers catch up later
No side has a majority (2 + 2 + 1)No writes anywhere until the network heals
The split healsCut-off nodes see the higher term and catch up; the old leader's uncommitted entries are overwritten

In every case at most one side commits, and a side without a majority stops instead of guessing.

Reads need the same care. A cut-off leader does not yet know it was replaced, so answering from its own copy could show B4-24 as free after B sold it. It either confirms with a majority before answering, or holds a leader lease, a promise that no other leader can exist until a time has passed, which saves that round trip but trusts the clocks. Careful implementations also make a leader step down once it stops hearing from a majority, and use a pre-vote so a node returning from a split cannot force a needless election.

This is the abstractions chapter's trade during a split, consistency over availability: bookers on the minority side get errors, and no seat is sold twice.

Part 3 · Leases, Pauses and Fencing

Leases and the clocks under them

Machines outside the group need roles too, such as which scheduler runs tonight's chart job. A holder that dies cannot hand its role back, so roles come as leases. A lease works like a library book with a due date: if you vanish, the book returns to the shelf on its own.

The grantor gives the holder a right for a fixed time, such as 10 seconds, and the holder renews it every 3 seconds or so. A dead holder stops renewing; once the lease expires, someone else may take the role, with no crash detection needed.

Lease length is a trade. With a 10-second lease, a crashed chart job waits up to 10 seconds for a standby. A 1-second lease fails over faster, but any hiccup longer than a second hands the role away, and renewals cost ten times the traffic.

Every lease is only as safe as the clock that times it. Three clock problems matter, each with a standard defence:

Clock troubleDefence
Clocks tick at slightly different ratesRenew at a third of the lease; stop acting a margin before it ends
The wall clock jumps after a time-sync fix or a manual changeTime leases with a monotonic clock, which only moves forward
The grantor's countdown starts after the holder askedThe holder starts its countdown when it sends the request, so it always expires first

Healthy clocks differ in rate by well under 0.1%, a few milliseconds over a 10-second lease, so stopping a second early covers drift easily. No margin helps a holder that has stopped running, which is the next page's problem.

Pauses and fencing tokens

Core deep dive

Every lock, lease and leader in this chapter depends on this page: what happens when the holder freezes past its lease.

A process pause stops a program while the world moves on: garbage collection, usually for milliseconds and occasionally for seconds; a host pausing a virtual machine to move it; memory swapped to disk. The chart job can check its lease, freeze for 15 seconds, then write berths after its lease has passed to a standby.

The fix is a fencing token, which works like token numbers at a bank counter: once token 34 is being served, someone waving token 33 is turned away. The lock service issues a number with every grant, always higher than the last, and the holder sends it with every write. The storage rejects any token lower than the highest it has seen.

Animated sceneA paused chart worker meets a fencing token0:19

Watch for the token numbers: the berths table keeps only the highest it has seen

Read it as steps

The first chart worker freezes past its lease. Watch which write the berths table accepts when both workers think they hold the lock.

Worker 1 believed it held the lock, and from its own view it did. The berths table, which sees both writes in order, settled it: a token lower than the highest seen is refused, however sure its sender is. Next: where that check lives, and when to skip the lock.

Check the token where the data lives

Why must the storage check the token, and not the worker? Because a pause can land between any check the worker makes and its write; only the storage sees writes in order. In a database the check is one more condition on the update:

sql
-- worker 2, token 34: changes 1 row
UPDATE berths SET passenger = 'WL-1', fence = 34
 WHERE berth = 'B4-23' AND fence <= 34;
-- worker 1 wakes, token 33: changes 0 rows
UPDATE berths SET passenger = 'WL-2', fence = 33
 WHERE berth = 'B4-23' AND fence <= 33;

Often the lock itself is unnecessary. When the contested data lives in one database, a conditional write (compare-and-set) settles the race in one round trip: the database applies the write only if its stated condition still holds. Two passengers racing for B4-23 need no lock: UPDATE seats SET status = 'held' WHERE seat = 'B4-23' AND status = 'available' changes 1 row for one and 0 for the other. Choose by what a double run would do:

You needUse
One winner among racing writers in one databaseA conditional update or a unique constraint
No lost updates on a shared rowA version checked on each write: WHERE version = 7
Less duplicate work; a rare double run is harmlessA plain lease-based lock, no fencing
One writer to a resource a double run would corruptA lease plus a fencing token the resource checks

A lock for efficiency can be a plain lease; a lock for correctness needs a token the resource checks, or it protects nothing.

When the resource cannot check tokens

An SMS gateway or payment provider will not compare your token. Send an idempotency key it honours; the lock then only reduces duplicates.

Part 4 · Coordination Services

A small store everyone agrees on

Who issues those leases and tokens? You rarely build consensus yourself. You run a coordination service: a small key-value store replicated by a 3- or 5-node consensus group, so every client sees changes in one order. Think of it as the notice board in a station master's office: short, official facts that everyone trusts. It holds megabytes to a few gigabytes, with values usually capped near a megabyte.

Five features do almost all the work:

FeatureWhat it does
Sessions and leasesA client stays alive by heartbeating; silence ends its lease
Ephemeral entriesKeys tied to a lease and deleted when it ends: leader keys, member lists, locks
WatchesA notification when a key or prefix changes, so nobody polls
Compare-and-set"Create if absent", "update only if still version 7"
Rising revisionsEvery change gets a higher number: ready-made fencing tokens

Together they let a client claim a role, lose it automatically when it dies, and let everyone else notice within about a second.

Two details separate safe use from subtle bugs. First, a linearizable read goes through a leader that confirms it still leads, so it is never stale; a cheaper read from any node may lag. Use the first for "am I still the leader?".

Second, a watch says something changed, not what is true now. Notifications arrive late and can be missed during a disconnect. etcd-style watches resume from the last revision seen; older ZooKeeper-style watches fire once and must be set again. Either way, act through a conditional write, never on a notification alone.

Recipes built on the store

With those five features, most coordination jobs follow one recipe: write a small fact conditionally, tie it to a lease if it should vanish with its owner, and let others watch it. The booking site uses it four ways:

UseHow it works
Leader electionEach chart scheduler tries to "create /chart/leader if absent" under its lease; losers watch the key and try again when it vanishes
MembershipEach live booking server keeps an ephemeral key with its address under /services/booking/; load balancers watch the prefix
ConfigurationThe tatkal opening time and rate limits sit at one key; servers watch it and reload within about a second
Partition mapWhich node leads each seat partition; routers cache the map and watch for new versions

Every row is small, changes rarely and matters to every server: that is what belongs here.

Locks with many waiters need one more trick. If 500 workers all wake when a lock frees, they stampede the service. Instead each creates a numbered entry and watches only the one just ahead, so a release wakes exactly one waiter, in arrival order.

Notice what is missing: bookings, passengers and payments. The service holds control facts, such as who leads and where data lives, never the user data itself.

Names you will hear

etcd: leases, watches and revisions behind a simple API; Kubernetes keeps its cluster state in it, and it suits new systems. ZooKeeper: older and mature, with sessions and numbered ephemeral entries; pick it where your stack already runs it. Consul: adds service discovery and health checks. etcd and Consul use Raft; ZooKeeper uses a similar leader-based protocol, ZAB.

What it costs, and where it belongs

Agreement is not free, so where should it sit? Each write costs a majority round trip plus a disk flush: a few milliseconds within a region. With batching, one group commits thousands to tens of thousands of small writes a second, plenty for control facts and far too few for user traffic.

Placement sets what the group survives and what each write costs:

LayoutSurvivesRough write time
3 nodes in 3 zones1 node, or a zoneA few ms
5 nodes in 3 zones, 2 + 2 + 12 nodes, or a zoneA few ms
5 nodes in 3 regions, 2 + 2 + 1A whole regionTens to hundreds of ms

Surviving a whole region costs every write a cross-region round trip, so keep a group per region and go global only for rare decisions. Keep the service off the hot path too: routers cache the partition map and watch it, and never call the service per booking.

A lock per request is the classic mistake. At 10 am the booking site runs 200 servers at 1,000 requests a second; a lock per request means 200,000 acquires a second plus the releases, ten to a hundred times what one group commits. Use consensus to decide who does the work, not to do the work.

Disks matter too: every commit waits for flushes, so a node sharing its disk with a busy logging agent slows every grant and can delay heartbeats into needless elections.

If the service goes down

Servers keep running on the cached partition map, so an outage freezes changes, not bookings. Leaders and lock holders stop when their leases lapse.

When not to use consensus

Consensus buys one agreed answer at the price of latency, three to five machines, and writes that stop when a majority is gone. Many problems do not need to pay that price. These are the common cases, with what to use instead:

SituationBetter choiceWhy
The contested data lives in one databaseA conditional write or unique constraintOne round trip, nothing to expire
Brief disagreement is harmless: who is alive, cache contents, like countsGossip, leaderless replicas or mergeable countersStays writable during a split
A write on every user requestA partitioned database, one leader per partitionConsensus only picks the leaders; the leaders carry the traffic
Frequent writes from several regionsA home region per record, copied out in the backgroundNo 100–200 ms majority round trip per write
A rare double run is harmlessA plain lease, no fencingLess machinery; accept an occasional duplicate

Reach for consensus when a wrong answer is worse than no answer; otherwise choose something that stays available.

The rule cuts both ways: if two owners would double-sell seats or corrupt a partition map, a cheaper scheme that is usually right is the wrong choice.

Later chapters lean on both sides of this rule: the key-value store uses gossip for membership because brief disagreement is fine there, while unique IDs lease machine numbers, the task scheduler fences workers with attempt numbers, and group chat gives each conversation one sequence owner under a lease.

Part 5 · Interview kit

The 45-minute answer

For "design a distributed lock service", spend the 40 minutes of design like this:

MinutesWhat you say and drawKey number or decision
0–5Acquire, renew and release named locks; at most one holder through crashes, pauses and splits; survive a zone. Do locks guard correctness or only save work?Correctness over availability
5–85,000 clients renewing every 3 s ≈ 1,700 renewals/s; 500 acquires/s; 50,000 locks × 200 B = 10 MBOne group, in memory; no sharding
8–13acquire(name, ttl) returns a token; renew, release(name, token), watch(name). One entry per lock: holder, lease, token, expiryToken = log index of the grant
13–22Any node forwards to the leader of 5 nodes over 3 zones (2 + 2 + 1); a grant commits on 3 of 5Survives a zone; a few ms per grant
22–37Deep dive: a paused holder's token-33 write refused after token 34; failover in 1–2 s; waiters queued one behind anotherLease 10 s, renewed every 3 s
37–40Losing 3 of 5 stops grants by design; a conditional write beats a lock when one database holds the dataSafety over availability

The depth is in pauses and failover: pick fencing for "what if a holder freezes?", failover for "what if the leader dies?", and queueing for 500 clients on one lock.

Say
"Five nodes spread 2 + 2 + 1 over three zones commit on any three: we survive a zone or two dead nodes, at a few ms per grant."
Say
"Storage rejects any token lower than the highest it has seen, so a paused holder cannot overwrite newer work."
Say
"If one database holds the data, a conditional update beats a lock: one round trip, nothing to expire."
Avoid
"The lock has a timeout, so it is safe." A holder can pause past it and still write.
Avoid
"Four nodes for extra safety." Four survive one failure, like three, and add a machine to fail.

Wrap-up

TermMeaning
QuorumA majority of the group: 2 of 3, 3 of 5
TermA numbered period with at most one leader; a higher term wins
CommittedStored by a majority, so never lost or changed
Split brainTwo nodes acting as leader at once
LeaseA right that expires unless renewed in time
Fencing tokenA number that rises with every grant; storage rejects lower ones
Ephemeral entryA key deleted when its owner's lease ends

Next, Designing a Key-Value Store spreads billions of keys across hundreds of machines, and shows when a store can loosen the majority rule to stay writable.

Part 6 · Check yourself

Quick check

Q1Why does an entry commit once a majority stores it, rather than the leader alone or every node?

Think it through, then check.

Q2At peak, writes to the seat database's 3-node group stall for about 2 seconds several times an hour, and the term climbs from 212 to 219. No node crashed. What is happening?

Think it through, then check.

Q3A 5-node group has 2 nodes in Mumbai, 2 in Delhi (30 ms away) and 1 on the US east coast (200 ms). How long does a write take with the leader in Mumbai, and in the US?

Think it through, then check.

Q4A double run of the chart job gives one berth to two passengers. A teammate proposes a 2-second lease, no fencing, for fast failover. What do you choose, and what is the trade?

Think it through, then check.

Q5The databases chapter's leaderless quorums (N = 3, W = 2, R = 2) make every read overlap the last write. Why can they not build a lock, when a 3-node consensus group can?

Think it through, then check.

Next chapter · 9 of 39Designing a Key-Value Store~32 min · 2 animated scenes