Replication quorums

Keep a value on N replicas, write it to W of them and read it from R. Take replicas down and find the settings where a read misses the latest write.

Replicas are numbered clockwise from the top. Click one to take it down or bring it back. A green dot marks the replicas that hold the latest write.

Every replica holds v1 · Delhi. Write a new version, then read it back.

Changing N starts again with every replica at v1 · Delhi.

A write succeeds once W replicas have it.

A read asks R replicas and keeps the newest version.

R + W > N3 + 3 = 6 > 5
Any R replicas include one of any W, so a read sees every write made with this W.
W > N/23 > 2.5
Any two writes made with this W share a replica, so the two sides of a network split can't both take writes.
Writes work with N − W
2down
Reads work with N − R
2down

5 of 5 replicas are up, so writes work and reads work.

What you are looking at

One key, stored on N replicas drawn round a circle. Each replica shows the version it holds and its value, and every one starts at v1, Delhi. The coordinator in the middle handles each request. A write succeeds once W replicas have stored the new version. A read asks R replicas and returns the highest version any of them holds. A green dot marks the replicas that hold the latest successful write.

A real coordinator sends every write to all N replicas and reports success once W of them confirm; the rest usually catch up a moment later. This lab writes to exactly W, the case where the others never heard about it: a dropped message, a slow link. Each write starts where the last one stopped, going clockwise, and reads start from a point of their own that moves on one place each time, so writes and reads drift past each other. With fewer than W replicas up, the coordinator refuses the write and sends it nowhere. Versions come from one counter here; real systems use timestamps or version vectors, covered below.

Why R + W > N works

If R + W is more than N, the replicas a read asks and the replicas a write reached can't fit into N without sharing at least one. With N = 5 and W = R = 3, whichever three replicas took the write, any three you ask include at least one of them, and the highest version wins, so the read returns the write. Replicas being down doesn't change this: the replica they share is one the read asked, so it was up.

Set W and R to 2 (2 + 2 = 4, not more than 5), write once and read a few times: some reads come back with the old value. Raise R to 4 (2 + 4 = 6) and every read returns the new one, though the write still reached only two replicas. Amazon's Dynamo paper (2007) gives N = 3, R = 2 and W = 2 as a common configuration: a majority each way.

The second check, W > N/2, is about writes meeting writes. When every write needs a majority, any two writes share a replica, so the two sides of a network split can't both accept writes, and two conflicting writes can't both succeed without some replica seeing both. Consensus protocols such as Raft and Paxos rely on majorities for the same reason. Set W to 2 and write twice: the lab tells you when a write shares no replica with the one before it.

Speed against failures

A write is only as fast as the W-th replica to confirm it, and a read as the R-th to answer, so smaller numbers are faster. They also survive more failures: writes keep working with N − W replicas down, reads with N − R. The box under the sliders keeps both counts. Choosing W and R is choosing where to pay:

  • W = N, R = 1: after a write every replica has it, so reading any one is enough, and reads are as fast as the quickest replica. But one replica down stops every write. Set W to 5 and R to 1, then take a replica down.
  • W = 1: writes are as fast as the quickest replica, but until the write is copied on, it lives on one machine. Set W to 1, write, take down the replica that got it, and read: no replica that answers has the write, and if that machine's disk fails, the write is lost for good.
  • A majority each way, W = R = 3 of 5: both checks pass, and reads and writes each survive two replicas down.

Cassandra lets each request choose, with its consistency levels. ONE waits for one replica, QUORUM for a majority (2 of 3 with three replicas) and ALL for every one. QUORUM writes with QUORUM reads overlap, since 2 + 2 > 3; ONE with ONE is faster and can miss a write.

In an interview

Define N, R and W, state the overlap rule with numbers, and say what each choice costs in speed and in failures survived. Then expect follow-ups:

  • Sloppy quorums and hinted handoff. In Dynamo, when some of a key's replicas can't be reached, the write goes to the next healthy nodes instead, with a hint naming the replica it was meant for, and is handed back when that replica recovers. Writes stay available, but R + W > N no longer promises overlap, because the W nodes that took the write may not be the ones a later read asks.
  • Read repair and anti-entropy. When a read finds replicas with older versions, the coordinator writes the newest version back to them. Replicas that nobody reads are caught up by a background comparison: Dynamo and Cassandra compare Merkle trees, hashes over ranges of keys, so only the ranges that differ are copied.
  • Conflicts. Two clients can write at the same moment. Last-write-wins keeps the version with the later timestamp and silently drops the other; Cassandra settles conflicts this way. Version vectors, which the Dynamo paper calls vector clocks, detect that two versions are concurrent and keep both for the application to merge.
  • Quorums alone aren't linearisable. Take N = 3 with R = W = 2, and a write that is still on its way: so far only replica 3 has it. A read that asks replicas 2 and 3 returns the new value; a read that starts a moment later and asks 1 and 2 returns the old one. To stop a later read seeing an older value, the reader has to write the newest version back to a quorum before it returns: read repair, done before answering rather than after. A write that failed after reaching some replicas, and clocks that disagree under last-write-wins, break it in other ways.
  • A timeout is not a failure. When the coordinator gives up waiting, the write may still have landed on some replicas. A retry has to be safe to apply twice: give each write an id, or make it set a value rather than change one.

The code

The lab's read: ask the first R replicas that are up, going round from a starting point, and keep the highest version. A real coordinator sends the read to every replica and finishes when the first R answer; keeping the newest is the same. The lab's write uses the same pick to choose its W replicas.

quorumRead.ts
type Replica = { up: boolean; version: number; value: string }; // The first count replicas that are up, going round from start.function pick(replicas: Replica[], start: number, count: number) {  const chosen: number[] = [];  for (let step = 0; step < replicas.length && chosen.length < count; step++) {    const i = (start + step) % replicas.length;    if (replicas[i].up) chosen.push(i);  }  return chosen.length === count ? chosen : null;} // Ask R replicas and keep the newest answer. Null: too few are up.function quorumRead(replicas: Replica[], start: number, r: number) {  const asked = pick(replicas, start, r);  if (!asked) return null;  let newest = replicas[asked[0]];  for (const i of asked) {    if (replicas[i].version > newest.version) newest = replicas[i];  }  return { asked, version: newest.version, value: newest.value };}
blur