LearnHLDReplication and quorums

Replication and quorums

Every copy of your data exists for one of two reasons: so you can survive losing a machine, or so you can serve more reads. Those are different jobs with different failure modes, and conflating them is how people end up surprised that their read replica served a profile edit that had already been saved.

The whole subject reduces to one question. When a write lands on one copy and a read hits another, what does the reader see?

Your answer

You write to the leader and immediately read from a follower, and the value is old. Is that a bug? What would you need to know to answer?

Leader and follower

One replica accepts writes. The others copy from it and serve reads. This is what almost every relational database does by default and it is the right starting point.

Figure 1. Writes have one path. Reads have several, and each one is a slightly different point in the past.

Follower B in Figure 1 is not broken. Replication lag is normal, it varies constantly, and it spikes exactly when you least want it to: during a large write, a schema change, or a burst of traffic. Any design that assumes followers are current is a design that works in testing and fails in production.

Synchronous or not

Replication mode
The leader acknowledges as soon as it has the write, and ships it onward whenever it can. Fast, and it keeps working when a follower is slow or gone. The cost is real: if the leader dies before the follower catches up, those acknowledged writes are gone, and the customer was told they succeeded.

Quorums

Leaderless systems like Dynamo, Cassandra and Riak drop the leader entirely. Write to several replicas, read from several replicas, and make the two sets overlap.

The rule is one line of arithmetic. Drag the sliders and watch the sets move.

Preset
3
2
2
W + R - N = 1 overlap, so reads see the latest write
Every read set shares at least 1 node with every write set, so a read always touches a replica that has the newest value. Writes survive 1 node failure, reads survive 1.

The picture is the proof. Write to the first W nodes, read from the last R, and the number they share is W + R - N. When that is at least one, every read touches a node that saw the last write, so the newest value is always in the response set and a version number picks it out. When it is zero or less, the sets can miss each other entirely.

What a quorum does not give you

R + W greater than N gives you a read that sees the latest completed write. It does not give you transactions, it does not order concurrent writes to the same key, and it does not prevent two clients writing at the same moment and producing two conflicting versions. That is a separate problem, solved with version vectors and either last write wins or application level merging.

Failover, and the two ways it hurts

When the leader dies, something has to promote a follower. Both parts of that are hard.

Deciding it is dead. The only evidence is silence, and silence is indistinguishable from a slow network. Set the timeout aggressively and you promote a leader that was merely busy. Set it generously and you are down for that long every time.

Two leaders at once. The old leader was not dead, just unreachable, and it is still accepting writes from clients that can still see it. Now two nodes both believe they are the leader, and both are accepting conflicting writes to the same rows.

1/6 Normal operation. Leader A takes writes, B follows along a few milliseconds behind.

The defence is a fencing token: every leadership term gets a monotonically increasing number, and the storage layer rejects writes carrying an old one. The deposed leader tries to write, gets refused, and finds out it is no longer in charge. Without fencing, “we promote a follower” is a sentence that hides a data loss bug.

Consistency, said plainly

CAP gets quoted more than it gets used. The useful version is short.

During a network partition you must choose between refusing requests and serving possibly stale data. There is no third option, and the choice is per operation rather than per system: a bank balance and an avatar image in the same product should answer differently.

The part people miss is what happens the rest of the time, which PACELC names. When there is no partition, you still trade latency against consistency, because a strongly consistent read means waiting for a quorum. That trade is live every single day, whereas partitions are rare, so it matters far more in practice.

The guarantees worth naming out loud

Read your writes: you always see your own updates. Usually done by routing a user’s reads to the leader for a short window after they write, which is cheap and solves the most visible symptom. Monotonic reads: you never see time go backwards, so pin a user to one replica. Consistent prefix: you never see an effect before its cause, which is what stops a reply appearing above the message it answers.

Break it

Replication health
healthy
healthylag climbingleader diessplit brainfenced
Healthy. Lag under 10ms. Reads go to followers, writes to the leader, and nobody can tell the difference from a single machine.

Trade-offs

ChoiceWhat you gainWhat you payPick it when
Asynchronous replicationWrites never wait on a replica, and a slow or dead follower cannot stop them.A leader failure loses every write it acknowledged but had not yet shipped.Read scaling and analytics replicas, where the leader is not the only copy that matters.
Semi synchronousEvery acknowledged write exists on at least two machines, so one failure loses nothing.Writes pay one extra round trip, and if no follower can confirm, writes stall.The default for anything you would be unhappy to lose. Most managed databases offer it.
Quorum with R + W > NNo leader to fail over, and reads always see the latest completed write.Every operation talks to several nodes, so latency tracks the slowest of them, and concurrent writes still conflict.Multi region, high write availability, and a workload that tolerates conflict resolution.
Read your writes routingRemoves the symptom users actually notice, at almost no cost.Extra load on the leader for a short window after each write, and it needs sticky routing.Any system with follower reads and users who edit their own data, which is most of them.

Interview replay

Interviewer
You add read replicas. A user updates their profile and then sees the old value. What happened?
The single most common real world consequence of replication, asked as a debugging question.
You
The write went to the leader and the read went to a follower that had not applied it yet. It is not a bug in the replica, it is replication lag, which is normal and spikes under load. The fix is read your writes: route a user’s reads to the leader for a few seconds after they write, or track the write position and only use a replica that has reached it.
Names it as expected behaviour rather than a fault, then gives two mechanisms. Not treating it as a bug is the part that signals experience.
Interviewer
Would you use synchronous replication instead?
Offering a plausible answer that is usually wrong.
You
Not to solve this. Fully synchronous means every write waits for every replica, so one slow follower slows all writes and one unreachable follower stops them. I would use semi synchronous, waiting for one follower, so an acknowledged write always exists on two machines. But that is about durability, and it does not fix stale reads on the other replicas.
Separates the durability problem from the staleness problem. They look similar and have different answers.
Interviewer
The leader becomes unreachable and you promote a follower. What is the risk?
Straight at split brain.
You
That the old leader was not actually dead, just partitioned, and is still taking writes from clients on its side. Two leaders writing conflicting rows, and reconciling that loses acknowledged data however you resolve it. The defence is a fencing token: an increasing term number that the storage layer checks, so the old leader’s writes are rejected the moment a new term starts.
Names the mechanism. Fencing is the concrete detail that separates having read about failover from having designed it.
Interviewer
When would you pick a quorum system over a leader?
Checking whether you reach for Dynamo style storage by default.
You
When I need writes to survive losing a whole region, or when write availability matters more than ordering. The cost is that concurrent writes to one key produce conflicting versions I have to resolve, either with last write wins, which silently drops data, or in the application. For a workload with a natural single writer per key, a leader is simpler and I would keep it.
Names the cost before the benefit, and ends by declining the fancier option for most cases.

Checkpoint

Checkpoint

1. N = 5, W = 2, R = 2. Can a read miss the latest completed write?

2. What does a fencing token prevent?

3. Which guarantee stops a user seeing their own profile edit disappear?

Say this in 60 seconds

Replicas exist either for durability or for read scaling, and those are different jobs. I would default to a leader with semi synchronous replication, so every acknowledged write is on at least two machines without waiting for every replica. Followers lag, always, and that lag spikes exactly under load, so any read from a follower is a read from slightly in the past. The symptom users notice is their own edit disappearing, and the fix is read your writes: route them to the leader for a few seconds after a write. On failover the risk is split brain, where the old leader was only partitioned and is still taking writes, so I would use fencing tokens that let the storage layer reject a stale leadership term. If I needed leaderless writes I would use a quorum with W plus R greater than N, and I would say up front that this buys latest-write reads and not transactions or conflict resolution.

IndGeek provides solutions in the software field, and is a hub for ultimate Tech Knowledge.