System designCore11 min

Quorums

Keep three copies with no leader, write to two, read from two, and you will always see the latest write. Quorums turn that overlap into a dial between speed, availability and freshness, and they have edge cases worth knowing before you trust them.

1 · The problem

With copies and no leader, which one is current?

An online shop keeps every shopping cart on three servers, called replicas, so a cart survives a dead server. There is no leader: any replica can take a write. That keeps the cart writable even while one server is down, which matters, because a cart that refuses an item is a lost sale.

Now follow one cart. You add a lamp. The write reaches replicas A and B, but C is restarting and misses it. A minute later the app reads your cart from C alone:

Writing to some replicas and reading from others can miss the latest write entirely. The lamp is safe on A and B, and the cart still looks empty.

The two obvious fixes both hurt:

  • Write to all three, read from any one. Reads are always current, but a single dead replica stops every write.
  • Write to any one, read from all three. Writes never stop, but a single dead replica stops every read.

A quorum sits between them: wait for some of the replicas on each side, chosen so that the two sides always meet.

2 · The idea

If every read set overlaps every write set, reads see the latest write

Three numbers describe a quorum system:

  • N, the number of replicas of each item.
  • W, how many must confirm a write before it counts as done.
  • R, how many must answer a read.

The rule is W + R > N. With N = 3, W = 2 and R = 2, the write lands on two replicas and the read asks two. Two plus two is four, but there are only three replicas, so at least one replica must be in both groups. That replica has the lamp.

The read gets two answers that may disagree, so each value carries a version, such as a counter or a timestamp, and the reader keeps the newest. Here is how the dial turns for N = 3:

W, R

Overlap?

With one replica down

Good for

W 2, R 2

Yes: 4 > 3

Reads and writes both work

The usual balance

W 3, R 1

Yes: 4 > 3

Writes stop; reads work and are fast

Data read far more than written

W 1, R 3

Yes: 4 > 3

Reads stop; writes work and are fast

Data written far more than read

W 1, R 1

No: 2 is not more than 3

Both work, but a read may be stale

Speed first; staleness is acceptable

A majority quorum is the common default: ⌊N ÷ 2⌋ + 1 replicas, which is 2 of 3 or 3 of 5. Using it on both sides gives overlap and survives the loss of a minority. It is the same arithmetic that consensus protocols rely on (Consensus & leader election), applied here to reads and writes instead of to decisions.

The setting is often chosen per request rather than once per database. Cassandra calls these choices consistency levels: ONE, QUORUM and ALL, among others. The original Dynamo design, built at Amazon for exactly this kind of shopping cart, most commonly ran N = 3, R = 2, W = 2.

Availability follows from the same numbers. Say each replica is down 1% of the time, independently of the others:

Requests wait for

Fails when

Unavailable

Any 1 of 3

All three are down

0.01³ = 0.0001%

2 of 3 (quorum)

Two or more are down

≈ 0.03%

All 3

Any one is down

1 − 0.99³ ≈ 3%

Waiting for all three is a hundred times worse than a quorum. Independence is the caveat that makes the table true: three replicas in one rack, on one power feed, fail together (Redundancy & failure domains).

3 · The bonus

A quorum waits for the fastest replicas, not the slowest

The coordinator sends a read to all three replicas at once and answers as soon as R of them reply. So a read's time is set by the R-th fastest replica, and a single slow replica is simply ignored. Say two replicas answer in 4 ms and 6 ms, and the third is in the middle of a long garbage-collection pause:

Read with R = 1
4 ms
Read with R = 2
6 ms
Read with R = 3
40 ms

Replicas answering in 4, 6 and 40 ms. A read waits for the R-th fastest answer: 4, 6 or 40 ms. A quorum read is almost as fast as the quickest replica and hides the slow one.

This is a quiet advantage over a single leader. With one leader, every write waits for that one machine, however slow it is right now. A quorum lets the fastest replicas carry each request, which cuts the tail of the latency curve.

4 · Catching up

Replicas that missed a write must be repaired

Replica C still has the old cart. Quorums tolerate that, but if nothing fixes C, a later failure of A or B leaves the lamp on only one replica. Three mechanisms bring stragglers up to date:

Mechanism

When it runs

What it fixes

Read repair

During a read that sees different versions

Writes the newest version back to the replicas that answered with an older one

Hinted handoff

While a replica is down

Another node keeps the missed writes as hints and replays them when it returns

Anti-entropy repair

In the background, on a schedule

Compares whole replicas and copies whatever differs, including data nobody reads

Read repair only fixes what people read, and hints are kept for a limited window: Cassandra keeps them for 3 hours by default. Both are best effort. Anti-entropy is the backstop, and it needs a cheap way to compare millions of rows between two servers without sending them all.

The tool is a Merkle tree: each leaf is a hash of a range of rows, and each parent is a hash of its children. Two replicas compare their roots. If the roots match, everything matches. If not, they compare the children and follow only the branches that differ:

Root hashdiffersCarts 0–4,999sameCarts 5,000–9,999differsCarts 5,000–7,499sameCarts 7,500–9,999differs: copy theseRoot hashdiffersCarts 0–4,999sameCarts 5,000–9,999differsCarts 5,000–7,499sameCarts 7,500–9,999differs: copy these

Two replicas compare a handful of hashes instead of ten thousand carts, and copy only the one range that differs.

One more relaxation is worth knowing. In a sloppy quorum, used by the original Dynamo, a write that can't reach its usual replicas is accepted by other healthy nodes and handed back later. Writes keep working through bigger failures, but the write may now sit on nodes that a read never asks, so W + R > N no longer guarantees overlap.

5 · The catch

Overlapping copies are not the same as one copy

W + R > N promises that a read overlaps the latest completed write. It does not make the replicas behave like a single copy (Consistency models calls that linearizable). The gaps show up in specific moments:

A read during a write. The new value has reached A but not yet B or C. One reader asks A and C and sees the new value; a moment later another reader asks B and C and sees the old one. Two people, one after the other, see time run backwards:

Replica C, still on the old value, answers both readers and is left out of the drawing. Reader 2 reads after reader 1 and sees an older cart.

Concurrent writes. Two devices change the cart in the same instant. If the newest timestamp simply wins (last write wins), one change is silently lost, and a clock that runs fast can make the older write the winner. Dynamo kept both versions instead and let the cart merge them; in its measurements, 99.94% of requests saw exactly one version.

Two more gaps:

  • A failed write that half happened. It reached one replica, not two, and was reported as failed. It is not rolled back, so later reads may or may not show it.
  • A replica restored from an older copy. The new value may now be on fewer than W replicas.

Two fixes exist for when you need more. A read can write back the newest value to a quorum before answering, which costs a second round trip. And an operation like reserve the last item only if it is still in stock needs real consensus, which Cassandra offers as lightweight transactions. Use them for the few operations that need them, not for every cart update.

6 · Across regions

Count the quorum where the latency is

The shop now runs in two regions, each with three replicas of every cart: six in all. A plain majority of six is four, so every quorum write must reach at least one replica across the ocean and waits for that round trip. Losing the link between regions stops quorum writes in both.

Level

Waits for

Speed

If the other region is cut off

QUORUM

4 of all 6 replicas

A cross-region round trip on every request

Neither region reaches 4 alone: requests fail

LOCAL_QUORUM

2 of the 3 replicas in your region

Local round trips only

Each region keeps working on its own

EACH_QUORUM

2 of 3 in every region

Waits for the farthest region

Writes fail

LOCAL_QUORUM is the usual choice. Reads and writes in the same region overlap, and a region keeps working when the other is unreachable. The price: a cart written in Europe and read in America a moment later may not show the change yet. For a cart, a user is almost always served by one region, so that is acceptable; for an account balance it might not be.

This is the CAP trade-off in practice (CAP & PACELC). During a partition, the side that can't reach its quorum must refuse requests, and the side that can keeps going. Choosing the level per request chooses, per request, which way to fall.

Check yourself

5 questions

1. N = 3, W = 2, R = 2, and one replica is down. What still works?
2. N = 3, W = 1, R = 1. You write a value and read it straight back. What can happen?
3. Three replicas answer in 4 ms, 6 ms and 40 ms. How long does a read with R = 2 take?
4. Two phones add different items to the same cart at the same moment. The database keeps whichever write has the later timestamp. What happens?
5. Carts live in two regions with three replicas each. Which level keeps requests local and still makes reads overlap writes made in the same region?

Takeaways

Remember this

  • With N replicas, writes confirmed by W and reads from R overlap whenever W + R > N, so a read sees the latest completed write.
  • N = 3 with W = 2 and R = 2 survives one failed replica on both reads and writes; waiting for all three fails a hundred times more often.
  • A quorum waits for the fastest R or W replicas, so one slow replica is hidden instead of slowing every request.
  • Read repair, hinted handoff and Merkle-tree anti-entropy bring replicas that missed writes back up to date.
  • Quorum overlap is not linearizability: concurrent writes, reads during writes and half-failed writes still surprise you, and last write wins can silently lose data.