Module A-1·30 min read

Raft leader election and log replication, quorums and split brain — plus why wall-clock timestamps cannot order events, and what TrueTime buys with atomic hardware.

JJS
Written by Jatin Jain Saraf · Senior Software Engineer

Module A-1 — Consensus, Clocks, and the Ordering Problem

What this module covers: Why getting several machines to agree on one value is genuinely hard rather than merely fiddly, starting from the impossibility result that shapes every real implementation. Quorums, why majorities prevent split brain, and why a two-node cluster is worse than one node. Raft in enough detail to reason about it — terms, elections, log replication, and the safety property that makes it correct — plus the latency floor consensus imposes and the rule that follows: use it for metadata, not for the data path. Then the half that causes more production damage: time. NTP drift and the monotonic-versus-wall-clock bug, why wall-clock timestamps cannot order cross-region writes, and how last-write-wins turns that into silent data loss. Lamport clocks, vector clocks and hybrid logical clocks as three different answers, what Spanner's TrueTime buys by paying for atomic hardware, and the discipline of never using a wall clock for correctness.


Agreement Is Hard Because You Cannot Tell a Dead Node From a Slow One

Module P-10 established the fact this module is built on: the only failure detector available over a network is a timeout, and a timeout cannot distinguish a crashed process from a paused one, a slow one, or one behind a broken route. Every hard problem in distributed coordination is a consequence.

Now add the thing you actually want. Five machines must agree on one value — who the leader is, what the shard map says, whether the lock is held — such that they never disagree, even if two of them crash and the network partitions.

There is a formal result about this, and it is worth knowing precisely because it explains why every real system looks the way it does. The FLP impossibility result: in an asynchronous system where messages can be arbitrarily delayed, no deterministic algorithm can guarantee consensus if even one process may fail. Not "it is difficult" — it cannot be guaranteed, because there is always an execution in which the algorithm fails to decide.

Real systems escape this in the same way, by weakening the model rather than the goal:

  • Assume partial synchrony. Messages usually arrive within some bound. Then use timeouts as a failure detector, accepting that a wrong guess costs availability (a spurious election) rather than correctness.
  • Give up liveness under sustained bad conditions, never safety. A Raft cluster with a flapping network may elect leaders repeatedly and make no progress. That is the designed behaviour: it stops rather than deciding two different values.

So every consensus protocol you will use is a machine for turning "we cannot be sure who is alive" into "a majority has agreed, and no other majority can have agreed to something else."

Analogy: a committee that must appoint one chair, whose members can only exchange letters, and where a member who goes quiet might be dead, asleep, or writing a very long letter. The rule that makes it work is not better letters — it is requiring a majority to sign the appointment. Two different majorities of the same committee must share at least one member, and that member will not sign twice for the same term. The overlap is the mechanism; everything else is bookkeeping.


Quorums: Majorities Overlap, Which Is the Entire Safety Argument

A quorum is ⌊n/2⌋ + 1 — a strict majority. The property that matters is that any two majorities of the same set intersect in at least one member, so a value committed by one majority cannot be contradicted by another.

NodesQuorumFailures toleratedNotes
110no fault tolerance, and no coordination cost
220worse than one node — either failure stops all writes
321the practical minimum
431same tolerance as 3, more cost, slower writes
532the standard choice for anything important
743rarely worth the latency

Two conclusions people get wrong.

Two nodes are strictly worse than one. With two nodes a quorum is both of them, so any single failure halts writes — you have doubled your failure surface and gained nothing. Every "we'll add a second node for redundancy" plan for a consensus system is wrong; the increment that buys something is the third.

Even numbers waste a node. Four tolerates the same single failure as three while requiring one more acknowledgement per write. Use odd counts.

And the thing majorities buy you: split brain is impossible. Partition five nodes into 3 and 2. The side of 3 can form a quorum and keeps operating; the side of 2 cannot and stops. There is never a moment when both sides commit conflicting values — which is precisely what CAP describes (Module P-10) as choosing consistency over availability on the minority side.

What a majority quorum does not do is prevent a node from believing it is still the leader. The old leader on the minority side may accept reads, answer health checks, and hold a lock it no longer owns. It cannot commit anything, because it cannot reach a quorum, but it can still do damage through side effects — which is the entire subject of Module A-2's fencing tokens.


Raft: Terms, Elections, and a Replicated Log

Raft is the consensus algorithm to reason with, because it was explicitly designed to be understandable and because it is what etcd, Consul, CockroachDB, TiKV and Kafka's KRaft mode implement.

Structure. One leader at a time; followers replicate its log. Time is divided into terms — a monotonically increasing integer, incremented on each election. A term is Raft's logical clock and its fencing mechanism at once: any message carrying a stale term is rejected, which is how a deposed leader is neutralised the moment it talks to anyone current.

Election. Each follower runs an election timeout, randomised (say 150–300 ms). If no heartbeat arrives before it fires, the follower increments the term, becomes a candidate, and requests votes. A node grants at most one vote per term. A candidate winning a majority becomes leader.

The randomisation is doing real work: with identical timeouts, every follower would become a candidate simultaneously, split the vote, and repeat indefinitely. Randomised timeouts make one node reliably fire first. This is Module A-6's jitter argument appearing at the bottom of the stack.

Log replication. Clients send writes to the leader, which appends to its log and sends AppendEntries to followers. Once a majority has persisted an entry, the leader marks it committed and applies it to its state machine. Committed means durable and irrevocable.

text

The safety property that makes it correct: a candidate can only win an election if its log is at least as up to date as the majority that votes for it. Combined with "a leader never overwrites its own committed entries," this guarantees that a committed entry is present in every future leader's log. That is the whole correctness argument, and it is worth being able to state, because it is what makes "committed" mean something.

Membership changes are the subtle part. Moving from a 3-node to a 5-node cluster naively creates a window where two disjoint majorities exist (2 of 3, and 3 of 5), so two leaders can be elected. Raft solves it with joint consensus — a transitional configuration requiring majorities of both old and new sets. The practical lesson: cluster membership changes are the most dangerous operation on a consensus system, they must go through the protocol rather than a config file, and one node at a time.

What consensus costs, and the rule that follows

Every committed write requires a round trip to a majority. So:

  • Latency floor = the RTT to the median-slowest quorum member. Same-AZ, that is under a millisecond. Cross-region, it is 50–150 ms per write, and no amount of engineering removes it, because it is the speed of light plus routing.
  • Throughput is bounded by the leader, which handles every write. Consensus does not scale writes; it makes them safe. Scaling means sharding into many consensus groups (Module P-6), each with its own leader — which is exactly what CockroachDB, TiKV and Spanner do.
  • Availability is bounded by quorum reachability, so a cluster spanning three regions survives a region loss and pays cross-region latency on every write.

Hence the design rule that matters more than any protocol detail: use consensus for metadata, not for the data path. Who is the leader, what is the shard map, which nodes are members, who holds the lease — these are small, infrequently-changed, and correctness-critical, so paying 5 ms or 100 ms is fine. Routing every user write through a consensus group is how you build a system with a 150 ms floor on every request.

This is why the common architecture is a consensus system beside your data store rather than underneath it: Postgres replication is not consensus, but Patroni uses etcd (which is) to decide who the primary is. The expensive guarantee is applied only to the decision that needs it.


Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.