How to spread keys across a changing set of servers without reshuffling the entire world every time one joins or dies.
The naive way to shard data is server = hash(key) mod N. It works perfectly until N changes. Go from 4 servers to 5 and almost every key's answer changes — roughly (N-1)/N of your data, about 80%, must move. Your cache empties, your database stampedes, your night is ruined.
Consistent hashing removes N from the equation. Instead of hashing keys into buckets, you hash both keys and servers into the same circular address space — typically 0 to 232−1, wrapped so that the largest value sits next to zero. A key belongs to the first server found by walking clockwise from the key's position.
Now the geometry does the work. A node only ever owns the arc between itself and its counter-clockwise neighbour. Delete a node and only that one arc is inherited by its clockwise successor — every other arc is untouched, because no other key's clockwise walk was affected.
A fixed circular key space (0 … 232−1) that never resizes. Because its size is constant, node membership changes don't change any key's position — only who is nearest.
Node positions held in a sorted structure; routing is a binary search for the smallest position ≥ hash(key), wrapping to the first if none. O(log N), no coordinator required.
Each physical server is hashed onto the ring V times (100–256 typical). Averaging many small arcs instead of one large one crushes load variance and lets you weight bigger machines.
For redundancy, keep walking clockwise past the owner to the next R distinct physical nodes. This is how Dynamo/Cassandra derive a preference list from pure geometry.
"srv-A#0" … "srv-A#255") and insert each resulting position into a sorted array or balanced tree.| Property | hash mod N | Consistent hashing |
|---|---|---|
| Keys moved when N→N+1 | ≈ K·(N−1)/N | ≈ K/N |
| Lookup cost | O(1) | O(log N) binary search |
| State each client needs | N | N·V ring positions |
| Load balance | Near-perfect | Needs virtual nodes to be even |
| Heterogeneous machines | No mechanism | Weight by V per node |
| Behaviour under churn | Global reshuffle | Local, bounded disruption |
The trade is explicit: you accept a logarithmic lookup and a larger routing table in exchange for bounded disruption. In a system where machines fail weekly, that bound is worth far more than the O(1).
ring_hash and maglev policies route a session key to a stable backend so connections survive fleet changes.1. Skipping virtual nodes. With one position per server, random placement gives wildly unequal arcs — a "balanced" scheme where one node quietly takes triple the traffic. V=1 is the most common broken implementation.
2. Hashing the node's IP or index. If the node's ring identity changes when it restarts on a new IP, or shifts because a peer was removed from a list, you have re-introduced the reshuffle you were trying to avoid. Hash a stable ID.
3. Confusing it with a consistency model. "Consistent" here means stable under membership change — it says nothing about CAP-style consistency, replication lag, or quorums. That is the next card's problem.
hash(key) mod N, and roughly how many under consistent hashing? Show the reasoning, not just the numbers.
Hint: compare K·(N−1)/N against K/N, and say precisely why the ring avoids touching the other arcs.