System DesignIntermediate7 min readPart 7 of 14

Consistent Hashing

Consistent hashing spreads data across servers so that very little has to move when a server is added or removed. It fixes the core problem with plain modulo hashing, where changing the number of servers moves almost every key.

Can you explain consistent hashing out loud?

I'm Alex. Read this, then I'll interview you on a design problem and push on the parts you skip.

The problem with modulo hashingCore idea

With modulo hashing, server = hash(key) % N. Change N and the answer changes for nearly every key, which means moving nearly all your data. At scale, that is unacceptable.

Key (hash)4 servers: hash % 45 servers: hash % 5Moved?
key1 (7)server 3server 2✗ moved
key2 (12)server 0server 2✗ moved
key3 (19)server 3server 4✗ moved
key4 (25)server 1server 0✗ moved

The hash ringHow it works

Consistent hashing places both keys and servers on a circle of hash values (0 to 2³² − 1). To find a key's server, hash the key and walk clockwise until you reach a server.

hash ring0 … 2³² − 1Server AServer BServer Ck1 → Ak2 → Bk3 → C
DiagramServers (squares) and keys (dots) share one ring. Each key belongs to the next server clockwise.

When a server is added, only the keys between it and the server before it move. When a server is removed, only its own keys move, to the next server clockwise.

ImplementationHow it works

A consistent hash ringTypeScript
class ConsistentHashRing {
  private ring = new Map<number, string>();
  private sortedKeys: number[] = [];

  addServer(server: string) {
    const h = this.hash(server);
    this.ring.set(h, server);
    this.sortedKeys.push(h);
    this.sortedKeys.sort((a, b) => a - b);
  }

  getServer(key: string): string {
    const h = this.hash(key);
    // First server clockwise (binary search would make this O(log n))
    for (const ringKey of this.sortedKeys) {
      if (ringKey >= h) return this.ring.get(ringKey)!;
    }
    // Past the last server: wrap around to the first
    return this.ring.get(this.sortedKeys[0])!;
  }

  private hash(s: string): number {
    let h = 2166136261; // FNV-1a, 32-bit
    for (let i = 0; i < s.length; i++) {
      h ^= s.charCodeAt(i);
      h = Math.imul(h, 16777619);
    }
    return h >>> 0;
  }
}

Virtual nodesPattern

With only a few servers, the gaps between them on the ring are uneven, so some servers get far more keys. Virtual nodes fix this: each physical server is placed on the ring many times (say 150), and the load evens out statistically.

ABC
Without virtual nodes: one server can end up with most of the keys.
ABC
With 150 virtual nodes each: close to an even split.

Adding and removing serversScale

Adding a server only moves the keys between it and its neighbour. With 3 servers and 1M keys, adding a 4th moves about 250K keys (25%), compared with about 750K (75%) under modulo hashing.

ApproachKeys moved when a server is addedBalance
Modulo hashing~all keysEven (while N is fixed)
Consistent hashing~1/N of keysUneven without virtual nodes
Consistent + virtual nodes~1/N of keysEven (150+ vnodes)

Where it is usedReal world

Amazon DynamoDB

Spreads data across storage nodes.

Apache Cassandra

Partitions data using a ring with virtual nodes.

CDNs

Akamai and Cloudflare route requests to edge servers.

Memcached clients

Spread keys across cache nodes.

Load balancers

Session affinity by hashing the client IP.

Common interview mistakesPitfalls

No virtual nodesDistribution is badly uneven, especially with few servers.
A poor hash functionUse MurmurHash3 or CityHash, not MD5 (slow) or Java’s default hashCode (poorly spread).
Ignoring server capacityGive bigger servers proportionally more virtual nodes.
Forgetting replicationThe ring decides placement, not copies. Replicate to the next few servers for fault tolerance.
No monitoringTrack keys per server to catch imbalance early.

In the interviewIn the interview

Frequently asked questionsFAQ

What problem does consistent hashing solve?

It distributes keys across a ring of nodes so that adding or removing a node remaps only a small fraction of keys. Naive modular hashing remaps nearly everything when the node count changes, causing mass cache misses; consistent hashing bounds the movement to about 1/n of the keys.

What are virtual nodes and why add them?

Virtual nodes replicate each physical server at many positions on the ring, smoothing out skew caused by uneven hash positions or different machine capacities. More virtual slots mean a server leaving or joining shifts only a balanced slice of keys, and heavier machines map to proportionally more slots.

Where is consistent hashing used in real systems?

Distributed caches like Memcached and DynamoDB-style stores use it to assign data to nodes, and load balancers use it for stable IP hashing so clients keep reaching the same server. It is the standard answer for any horizontally scaled keyed lookup tier.

Now explain consistent hashing to me out loud

I'll give you a design problem and push on the trade-offs, like a real interviewer.

Practice with Alex

Keep readingKeep reading

Ready to practice?

Reading is step one. Saying it out loud is step two.

Start a mock interview with Alex, get pushed on the parts you skip, and see your hiring signal right after.