Latticework

Command Palette

Search for a command to run...

System Design Fundamentals

Consistent Hashing

24 min

Explanation

Networking Basics' load-balancing module distributed REQUESTS round- robin, but that only works when requests are stateless and interchangeable. Sharding DATA across servers is a different problem: each key needs to consistently land on the SAME server every time, but naive hash(key) % num_servers breaks badly when a server is added or removed — changing num_servers reshuffles nearly every key's assignment at once. Consistent hashing fixes this by placing both servers and keys on the same circular hash space (a "ring"): a key belongs to whichever server's point comes next going clockwise. Each server gets several points on the ring (virtual nodes) for a more even spread.

import hashlib

def deterministic_hash(s):
    return int(hashlib.md5(s.encode()).hexdigest(), 16) % (2 ** 32)

def build_ring(nodes, num_virtual=3):
    ring = {}
    for node in nodes:
        for v in range(num_virtual):
            point = deterministic_hash(f"{node}-{v}")
            ring[point] = node
    return ring
Try it

Note this uses hashlib.md5, NOT the simple polynomial hash from Kafka's topics-partitions module -- md5 spreads similar-looking strings (like 'node-a-0' vs 'node-a-1') much more evenly across the full hash space, which matters here because the RING needs good spread, not just 'any deterministic mod-N bucket' like Kafka's simpler partition count did.

Loading editor…
Explanation

The payoff: adding a 4th server to a 3-server ring only remaps the keys that happen to fall in the ring segment now claimed by the new server's virtual nodes — everything else stays exactly where it was. A quick empirical check confirms this: hashing 200 sample keys against a 3-node ring, then again against a 4-node ring, only about 8% of keys actually move to a different node — versus nearly 100% under naive hash(key) % num_servers, since changing the modulus from 3 to 4 reshuffles almost every key's remainder.

Exercise

Using the provided `deterministic_hash` and `build_ring`, write `assign_key_to_node(ring, key)`: hash `key`, then walk the ring's sorted hash points and return the node at the FIRST point `>=` the key's hash — wrapping around to the smallest point if the key's hash exceeds every point on the ring.

Quiz

Networking Basics' load-balancing module covered simple round-robin distribution. Why does adding or removing a SERVER matter so much more for a naive `hash(key) % num_servers` scheme than for consistent hashing?

Checkpoint

You can implement consistent hashing with virtual nodes, and understand why it minimizes key reassignment when the number of servers changes — unlike naive modulo-based sharding.