Chapter 04 / 10 · Distributed Systems

Replication and consistency

Copies make a system available. They also make “what is the current value?” a real question.

You replicate data for three reasons, and it is worth naming which one you are buying: surviving a machine’s death (durability, availability), putting data near its readers (latency), and spreading read load. The price is one question that never goes away: when the copies momentarily disagree, what does a read return?

Leader–follower, and the shape of lag

The workhorse arrangement: writes go to one leader, which streams them to followers. The first design decision is when the leader acknowledges:

ModeAck whenYou gainYou risk
Asynchronousleader has itlowest latencyleader dies → acknowledged writes lost
Semi-synchronousleader + one followerno single-node lossslightly slower; the usual compromise
Synchronous (all)every followerstrongest durabilityone slow node stalls all writes — rarely used as stated

Because followers run behind, lag surfaces as concrete, nameable anomalies — learn them by the user story: you post a comment, refresh, and it is gone (read your own writes violated — your write hit the leader, your read a stale follower); you refresh twice and the comment flickers in and out (monotonic reads violated — second read hit a more stale replica); an answer appears before the question it replies to (consistent prefix violated). Each has a standard patch — pin a user’s reads to the leader briefly after their writes, pin a session to one replica, order causally related items through one partition — but you must know you are buying the patch.

Failover is the other sharp edge. Detecting a dead leader is Stage 1’s ambiguity all over again (slow ≠ dead); promoting a follower during async lag can silently discard the last acknowledged writes; and the old leader coming back convinced it still leads is split brain — two leaders accepting conflicting writes. Doing this safely is precisely the consensus problem, which is why Stage 4 exists.

The consistency ladder

A consistency model is the honest label on the jar — a contract about which read results are legal. The rungs you will actually discuss:

ModelThe promiseFeels like
Linearizableas if one copy; every op atomic at some instant; reads see the latest writea single machine — the gold standard, at a latency price
Sequentialone global order everyone agrees on, but not tied to real timeconsistent, possibly stale together
Causalwhatever happened-before is seen in order; concurrent things may differconversations make sense; often the sweet spot
Session guaranteesread-your-writes, monotonic reads — per client“I am not confused about myself”
Eventualstop writing and replicas converge, eventuallyanything goes, briefly

The professional skill is naming the rung per piece of data: the account balance wants linearizable; the like counter is happily eventual; the comment thread wants causal. And read CAP narrowly, because it is narrow: during a partition, a system must choose between serving possibly-stale answers and refusing to answer. That is all it says. On a healthy network the operative trade is latency versus freshness — waiting for more replicas buys stronger answers at slower speeds.

Quorums — the dial

write · W = 3read · R = 3n1n2n3n4n5R + W > N → the sets must share a node — here n3 — so some read replica has the new value
Fig 2 · Quorums — overlap is the mechanism, not magic

Leaderless stores (the Dynamo family) make the trade tunable per request: write to W of N replicas, read from R, and if R + W > N the read set must overlap the write set, so at least one consulted replica has the newest value (the client or coordinator reconciles versions — vector clocks from Stage 2 report which). With N = 3: W = 2, R = 2 balances both paths; W = 3, R = 1 makes reads cheap and writes fragile; W = 1, R = 1 is fast and guarantees nothing. Production wrinkles to know by name: sloppy quorums (during a partition, accept writes on stand-in nodes to stay available) and hinted handoff (those stand-ins deliver the writes home later) — availability preserved, overlap guarantee temporarily traded away.

One more tool for the concurrent-writes problem deserves a name: CRDTs — data types (counters, sets, registers) built so concurrent updates merge deterministically by construction, no coordination needed. Where your data fits one (likes, presence, shopping carts), conflict resolution stops being your code’s problem at all.