The problem with modulo hashing
3 cache nodes, key "user:42"
slot = hash("user:42") % 3 → node 1
Add node 4:
slot = hash("user:42") % 4 → node 2 ← MOVED! cache miss storm
When StreamHub expanded Redis from 4 to 6 nodes using naive modulo, cache hit ratio dropped from 92% to 41% until keys repopulated — a classic cache stampede on the database.
The hash ring
New node E joins → only ~1/N keys move, not all keys.
Ring mechanics
- Hash space is a fixed ring (0 to 2³²−1 or 0 to 1.0).
- Each node is placed at one or more positions on the ring (via hash of node ID).
- Each key is hashed to a position on the ring.
- Walk clockwise from the key's position — the first node encountered owns the key.
- Adding a node steals only keys between its predecessor and itself.
Only keys in the affected arc move — typically 1/N of total keys when adding one of N nodes.
Virtual nodes (vnodes)
Physical machines get multiple positions on the ring for even distribution:
Physical node A → vnode A0, A1, A2, A3 on ring
Physical node B → vnode B0, B1, B2, B3 on ring
Without vnodes, uneven key density clusters on a few nodes. Redis Cluster and Dynamo use vnode-style partitioning.
# Redis Cluster — key must include hash tag for multi-key ops
SET user:{42}:session abc123
GET user:{42}:profile
# {42} ensures both keys land on same slot
The {...} hash tag forces related keys to the same slot — required for atomic multi-key operations.
Consistent hashing use cases
| System | What is hashed | Purpose |
|---|---|---|
| Distributed cache | Cache key | Route key to correct Redis/Memcached node |
| Load balancer | Client IP or session ID | Sticky routing with minimal remapping |
| Database sharding | Partition key (creator_id) | Stable shard assignment |
| CDN / object store | Object key | Even distribution across storage nodes |
Distributed cache
What is hashedCache keyPurposeRoute key to correct Redis/Memcached nodeLoad balancer
What is hashedClient IP or session IDPurposeSticky routing with minimal remappingDatabase sharding
What is hashedPartition key (creator_id)PurposeStable shard assignmentCDN / object store
What is hashedObject keyPurposeEven distribution across storage nodes
Adding and removing nodes
Adding a node:
Before: keys K1–K5 → nodes A, B, C
Add D between B and C:
Only keys that mapped to C and fall between B and D now map to D
~1/(N+1) keys move
Removing a node:
Keys owned by the removed node transfer to its clockwise successor. Plan capacity so successors absorb the load.
# StreamHub cache expansion runbook
steps:
- add_new_node_with_vnodes
- wait_for_key_migration_background
- monitor_hit_ratio_recovery
- remove_old_node_if_replacing
expected_hit_ratio_dip: temporary_5-10_pct
Comparison with alternatives
| Aspect | Modulo hash | Consistent hash |
|---|---|---|
| Node add/remove | ~100% keys remap | ~1/N keys remap |
| Implementation | Trivial | Ring + vnodes + gossip |
| Load balance | Even if hash uniform | Needs vnodes for even spread |
| Used by | Toy examples | Redis Cluster, Cassandra, Dynamo |
Node add/remove
Modulo hash~100% keys remapConsistent hash~1/N keys remapImplementation
Modulo hashTrivialConsistent hashRing + vnodes + gossipLoad balance
Modulo hashEven if hash uniformConsistent hashNeeds vnodes for even spreadUsed by
Modulo hashToy examplesConsistent hashRedis Cluster, Cassandra, Dynamo
Hot keys and mitigation
Consistent hashing does not fix hot keys — if every request hits video:viral_001, one node still melts.
Hot key mitigations
- Local cache on app server for ultra-hot keys.
- Key splitting —
video:viral_001:copy0…copy7spread load. - Read replicas behind the owning node.
- Pre-warm cache before anticipated traffic spikes.
# Hot key fan-out read (pseudocode)
def get_view_count(video_id: str) -> int:
if is_viral(video_id):
replica = random.randint(0, 7)
return cache_get(f"views:{video_id}:r{replica}")
return cache_get(f"views:{video_id}")
Rendezvous hashing (alternative)
Highest Random Weight (HRW) hashing picks the node with the highest hash(node, key) score. Simpler than a ring for small node counts; consistent hashing scales better for large dynamic clusters.
Quick recall
Everything you need if you only revisit this box.
- Modulo hashing remaps most keys when node count changes; consistent hashing minimises movement.
- Keys and nodes sit on a ring; each key belongs to the next node clockwise.
- Virtual nodes spread load evenly across physical machines.
- Redis Cluster uses hash slots;
{tag}groups related keys on one slot. - Used for distributed caches, shard routing, and sticky load balancing.
- Hot keys are a separate problem — split keys or replicate reads.
Test yourself
Answer these before moving on — recall is what makes it stick.