SD System Design In Depth
0%
lesson system-designload-balancinghashing

Consistent-hashing load balancing

Module 3.1: Network Protocols & Service Communication Updated Sep 17, 2026
📄 Cheat Sheet
Practical Load Balancing with Consistent Hashing
Google TechTalks Practical Load Balancing with Consistent Hashing Watch on YouTube ↗

Given by the Vimeo engineer who implemented consistent hashing with bounded loads in HAProxy; it covers the ring, virtual nodes and the bounded-load extension described in this unit, with production results.

0:00 / --:--

Under the Hood: Sticky Routing & Cache Locality

Traditional load balancing sends requests to any available server. For stateful caching tiers (e.g., in-process memory, local SSD caches), routing requests randomly forces every node to cache the whole working set, cutting effective cache capacity by about N times and lowering hit rates. Simple modulo hashing (hash(key) % N) achieves sticky routing, but adding or removing a single server shifts nearly 100% of keys, triggering a devastating cache stampede. Consistent Hashing solves this by ensuring that scaling moves only K/N keys.

Consistent Hashing with Virtual Nodes

flowchart TD subgraph HashRing ["Circular Hash Ring (0 to 2^32 - 1)"] V1["Server A (vnode 1)"] K1["Key 'user:101' -> Routed to Server A"] V2["Server B (vnode 1)"] K2["Key 'user:102' -> Routed to Server B"] V3["Server A (vnode 2)"] end K1 -.->|"Clockwise Seek"| V1 K2 -.->|"Clockwise Seek"| V2

Under the Hood: Bounded-Load Consistent Hashing

Standard consistent hashing can still create hot spots if a single partition key goes viral (e.g., a breaking news post). Google Research introduced Consistent Hashing with Bounded Loads (used in Vimeo and HAProxy):

  • Each server is assigned a maximum capacity threshold: 1 + ε times the average cluster load (e.g., 1.25×).
  • When a request hashes to server S, the load balancer checks if S is currently at or above its load ceiling.
  • If overloaded, the load balancer skips S and walks clockwise along the ring to the next available virtual node, strictly capping load while preserving maximum possible cache affinity.

Worked example: how many keys move

A cache tier has 10 servers and 100 million keys.

  • Modulo hashing (hash mod N): going from 10 to 11 servers, a key stays put only if hash mod 10 equals hash mod 11, which happens for about 1 in 11 keys. So roughly 91 million keys (about 91%) move, and the cache hit rate collapses while the database absorbs the misses.
  • Consistent hashing: the new server takes over about 1/11 of the ring, so roughly 9 million keys (about 9%) move, all onto the new server. The other 10 servers keep their contents.

Virtual nodes: with a single point per server on the ring, the largest arc can easily be 2 to 3 times the average. With about 100 to 200 virtual nodes per server, the load spread typically tightens to within roughly 10% of the mean. The cost is a larger ring lookup table, still tiny (2,000 entries for 10 servers), searched by binary search.

Bounded loads: with a capacity factor of 1.25, no server may hold more than 1.25 times the average current load. If a key's home server is full, the request walks clockwise to the next server with spare capacity. Vimeo reported that this change in HAProxy made bandwidth across its cache servers far more even, at the cost of a small reduction in cache hit rate.

flowchart LR K["Key user:42 hashes to position 7,300"] --> R{"Home server A at or over 1.25 x average load?"} R -- "No" --> A["Serve from server A"] R -- "Yes" --> B["Walk clockwise to next server B"] B --> C{"Server B under its cap?"} C -- "Yes" --> BS["Serve from server B"] C -- "No" --> D["Keep walking to the next server"]

Variants and trade-offs

SchemeKeys moved on changeBalanceNotes
Modulo hashingAlmost allGoodOnly for fixed N
Ring with virtual nodes (Karger et al. 1997)About 1/NGood with enough vnodesUsed by Cassandra, DynamoDB lineage, Memcached clients
Rendezvous (highest random weight)About 1/NGood without vnodesO(N) per lookup; simple and memory-light
Jump consistent hash (Google 2014)About 1/NVery evenServers must be numbered 0 to N-1; removing from the middle is hard
Maglev hashingSmallVery evenLookup table for fast packet steering in L4 balancers
Bounded-load consistent hashing (Mirrokni, Thorup, Zadimoghaddam 2016)Slightly more than 1/NCapped at (1 + epsilon) times averageHAProxy, Vimeo, Envoy supports a similar option

Failure modes

  • Clients with different server lists: if two clients see different membership, they send the same key to different servers and caches diverge.
  • Cascading overload: when a server dies, its whole arc moves to the next server clockwise unless virtual nodes spread it across many.
  • Cold server after join: the new server starts with an empty cache, so the database briefly sees about 1/N extra misses.
Check yourself Question 1 of 3
Why random routing hurts caches recall
From: Under the Hood: Sticky Routing & Cache Locality

A tier of N servers each keeps an in-process cache. Why does routing requests at random, instead of by key, hurt the hit rate?

Consistent Hashing Ring Visualizer
O(log N) Route

Observe how keys are distributed along a 360° circular hash ring. Add or remove nodes to see minimal key rebalancing in action!

Nodes: 4 | Virtual Nodes/Node: 3
0°
90°
180°
270°
Ring Size: 2^32
Clockwise Lookup
// Consistent Hashing Event Log
[INIT] Cluster established with Node_A, Node_B, Node_C, Node_D.
[READY] Binary search (upper_bound) active for ring lookups.
Architecture Challenge: Consistent Hashing Ring Mechanics
Advanced
Context / Scenario: Distributed cache storing 10 million user session tokens across 10 cache servers.
Problem: In a consistent hashing ring with N caching nodes, a server crashes. What fraction of total keys must be remapped to different nodes?
A Approximately 1/N of keys (only the keys that were mapped to the crashed node).
B 100% of all keys must be re-hashed and moved.
C 0% because keys are duplicated on every single node.
D 50% of the keys on neighboring nodes.

Key Takeaways

Consistent hashing maps keys and servers onto a circular 2^32 integer ring, relocating only K/N keys upon scaling.
Virtual nodes (100-250 per physical host) greatly reduce non-uniform hash distribution skew.
Google's Bounded-Load algorithm prevents hot-key server crashes by overflowing traffic to the next ring node.
Was this lesson helpful? Spot an issue or have a suggestion? Let us know on GitHub.
Report an issue