Question presented to candidate:
"In a replicated key-value store like Dynamo or Cassandra, each key lives on N replicas, and you configure how many must acknowledge a write (W) and answer a read (R). What is a quorum, why does W + R > N matter, and how would you set W and R for different workloads?"
What a strong answer should cover:
Definitions: N replicas per key, a write succeeds after W acknowledgements, a read waits for R answers and returns the newest version
The overlap rule: W + R > N forces every read set to share at least one replica with every write set, so a read meets the latest acknowledged write
The trade-off: lower W or R means faster, more available operations and possible stale reads; the common default is a majority for both (N=3, W=2, R=2), which survives one failure
How replicas converge: read repair, anti-entropy, and versions (timestamps or vector clocks) to pick the winner
Limits: sloppy quorums with hinted handoff break the overlap guarantee; quorums alone are not linearizable under concurrent or partially failed writes
Real knobs: Cassandra ONE, QUORUM (floor of RF/2, plus 1), LOCAL_QUORUM, ALL
Code / implementation expected: Optional โ the overlap rule and availability table matter most; the example enumerates every write and read set for N=3.
quorum
consistency
2
Try it yourself
Sketch your approach before you read the solution. That is what the interview tests.
Stuck? Get a hint.
A short nudge toward the approach. It will not give the answer away.
3
Solution
Target Audience: Beginners to distributed systems who know that databases can keep copies of data on several machines.
Difficulty: Medium
Verified with: Node 22.22, Python 3.12, Go 1.24 and Java 21 (all four print identical output). Cassandra consistency levels are cited from the DataStax Cassandra documentation; Dynamo techniques from the Dynamo paper (SOSP 2007) as summarised in course material.
How to read this doc: Every idea is explained in plain language first, then tagged with ๐ Interview term: so you also learn the words an interviewer expects. Numbers come from running the example; the Verified section quotes its full output.
1. Why This Even Matters โ A Story First
Three friends each keep a copy of the group's holiday plan. When the plan changes, you text the change, but you only wait until two of them reply "got it" before you move on; the th
The solution is hidden so you can try first
14 min read ยท 13 sections
4
Read the code
N=3 quorums: stale reads for every W and R, availability under failures, read repair, sloppy quorum
// Read/write quorums on N = 3 replicas: when W + R > N a read always meets the newest write.// Replicas are in-process objects {version, value}; "down" and "missed the write" are flags.const N = 3;
const names = ["r1", "r2", "r3"];
functionsubsets(k) { // every set of k replica indexes, in lexicographic orderconst out = [];
constgo = (start, cur) => { if (cur.length === k) { out.push(cur.slice()); return; } for (let i = start; i < N; i++) { cur.push(i); go(i + 1, cur); cur.pop(); } };
go(0, []); return out;
}
functionread(reps, set) { // newest version among the replicas that answeredlet best = null;
for (const i of set) if (best === null || reps[i].version > best.version) best = reps[i];
return best;
}
const configs = [[1, 1], [1, 2], [2, 1], [2, 2], [3, 1], [1, 3]];
console.log("1) All replicas hold v1=blue. Then v2=green is written to exactly W replicas.");
console.log(" Every possible write set x every possible read set:");
console.log("W R W+R>N stale reads");
for (const [W, R] of configs) {
let stale = 0, total = 0;
for (const ws ofsubsets(W)) for (const rs ofsubsets(R)) {
const reps = names.map((_, i) => (ws.includes(i) ? { version: 2, value: "green" } : { version: 1, value: "blue" }));
total++; if (read(reps, rs).version !== 2) stale++;
}
console.log(`${W}${R}${String(W + R > N).padEnd(5)}${stale} of ${total}`);
}
console.log("\n2) Availability: can the operation still reach enough replicas?");
console.log("W R 1 down: write/read 2 down: write/read");
for (const [W, R] of configs) {
constok = (need, down) => (N - down >= need ? "ok" : "FAIL");
console.log(`${W}${R}${(ok(W, 1) + "/" + ok(R, 1)).padEnd(19)}${ok(W, 2)}/${ok(R, 2)}`);
}
constshow = (reps) => reps.map((r, i) =>`${names[i]}=v${r.version}:${r.value}`).join(" ");
console.log("\n3) N=3, W=2, R=2 with read repair.");
let reps = names.map(() => ({ version: 1, value: "blue" }));
reps[0] = { version: 2, value: "green" }; reps[1] = { version: 2, value: "green" }; // r3 was partitionedconsole.log(" after write v2 (r3 missed it): " + show(reps));
const got = read(reps, [1, 2]);
console.log(` read from r2,r3 -> v${got.version}:${got.value} (r3 answered v1, newer version wins)`);
for (const i of [1, 2]) if (reps[i].version < got.version) reps[i] = { ...got };
console.log(" after read repair: " + show(reps));
console.log("\n4) Sloppy quorum: r1 and r2 are down, W=2.");
reps = names.map(() => ({ version: 2, value: "green" }));
const up = [2], W4 = 2;
console.log(` strict quorum write v3: ${up.length >= W4 ? "ok" : "FAIL"}, only ${up.length} of the 3 home replicas is up`);
for (const i of up) reps[i] = { version: 3, value: "red" };
const hint = { version: 3, value: "red", for: "r1" };
console.log(" sloppy quorum write v3: ok, stored on r3 and on stand-in node h4 with a hint for r1");
console.log(` r1 and r2 recover; read from r1,r2 -> v${read(reps, [0, 1]).version}:${read(reps, [0, 1]).value} (stale: the overlap was on h4, not a home replica)`);
reps[0] = { version: hint.version, value: hint.value };
console.log(` hinted handoff h4 -> ${hint.for}; read from r1,r2 -> v${read(reps, [0, 1]).version}:${read(reps, [0, 1]).value}`);
5
Discussion
Other approaches, follow-ups and how it went in real interviews.