Configurable Consistency: Coordinators and r/w/n Quorums
In one line: the first functional requirement was a configurable service. This lesson is where that gets delivered — one dial that lets the same design serve a cart that must never reject a write and a lookup that must always be fresh.
Finding the coordinator
There are two ways for a client to select a node:
| Approach | How it works | Benefit |
|---|---|---|
| Generic load balancer | Route the request to a load balancer, which forwards it on | The client isn't linked to the store's code — it stays simple |
| Partition-aware client library | The client knows the ring and routes directly to the coordinator | Lower latency — fewer hops, since the client goes straight to the right server |
Both are legitimate. The trade is client simplicity against a saved network hop — the same choice load balancing framed as server-side versus client-side balancing.
The knobs
With n = 3 in the top n of the preference list, three copies are maintained. Assuming nodes A, B, C, D, E in clockwise ring order, a write on A places copies on B and C — the next nodes clockwise.
Now two more variables:
r— the minimum number of nodes that must be part of a successful read.w— the minimum number of nodes involved in a successful write.
If r = 2, the system reads from two nodes when data is stored on three.
We must pick r and w such that at least one node is common between them, which ensures readers get the latest-written value. That gives the invariant:
r + w > n
What each configuration does
| n | r | w | Description |
|---|---|---|---|
| 3 | 2 | 1 | Not allowed — violates the constraint r + w > n |
| 3 | 2 | 2 | Allowed — fulfills the constraint |
| 3 | 3 | 1 | Speedy writes, slower reads — readers must reach all n replicas for a value |
| 3 | 1 | 3 | Speedy reads from any node, slow writes — every write must reach all n nodes synchronously |
How a write actually works
With n = 3 and w = 2:
Precisely:
- On receiving a
put(), the coordinator produces the vector clock for the new version and writes it locally. - It sends the n highest-ranking nodes the updated version and new vector clock.
- The write is successful if at least
w-1nodes respond — the coordinator wrote to itself first, so that totalswwrites. - The remaining node is updated asynchronously.
How a read actually works
- Requests go to the n highest-ranked reachable nodes in the key's preference list.
- The coordinator waits for
ranswers before returning results to the client. - If it receives several datasets it regards as unrelated — divergent histories needing reconciliation — it returns all of those versions.
- The conflicting versions are then merged, and the resulting value is rewritten to override the previous versions.
That last step is read repair: the act of reading a conflict is what triggers its resolution and writes the merged result back.
Latency is set by the slowest replica in the quorum
The latency of a get is determined by the slowest of the r replicas. As r increases, more replicas must respond, which increases latency and decreases availability — while making the system more consistent, since querying more replicas raises the chance of seeing the latest value.
This is tail latency from the Foundations module: you are not waiting for the average of r nodes, you are waiting for the worst of them. Raising r from 1 to 3 does not triple consistency and add 3x latency — it adds the tail of three samples, which is much worse than the mean.
Where the design stands
At this point the design satisfies scalability (consistent hashing plus virtual nodes), availability (peer-to-peer replication), conflict resolution (vector clocks), and configurability (r/w/n quorums).
The one requirement still outstanding is fault tolerance — what happens when nodes are actually down rather than merely slow. That is the next lesson.
Key takeaway
r + w > n fixes a budget; where you spend it is a product decision. Low w buys write availability, low r buys read latency, and no configuration gives you both.
Interview signal by level
| Level | What a strong answer sounds like |
|---|---|
| L4 | "We use quorums so reads and writes agree." |
| L5 | States the invariant and applies it: "r + w > n so the sets overlap — 3/2/2 as a balanced default." |
| Staff+ | Tunes per workload and prices it: "the cart runs w=1 so a write is never rejected, and pays with r=3. Read latency is the slowest of the r replicas, not the average — so raising r buys consistency at the tail, which is the expensive place to pay." |
Next: what happens when nodes genuinely fail.