Scaling Memcached: Implementing Consistent Hashing to Prevent Cache Storms
Learn how to implement consistent hashing in Memcached to prevent cache storms and maintain stability when adding or removing nodes from your cluster.
15 Oct 2025, 00:59 UTC

The Problem: The Thundering Herd During Scaling
In a standard modulo-based hashing scheme (key % N), adding or removing a single server changes the denominator for every single request. This causes a massive redistribution of keys, effectively invalidating the entire cache. For high-traffic applications, this triggers a "cache storm," where the backend database is suddenly overwhelmed by requests for data that was previously cached but is now mapped to a different node.
The solution is Consistent Hashing. By mapping both servers and keys onto a logical ring, you ensure that adding or removing a node only affects a small fraction (1/N) of the total keys, maintaining system stability during cluster resizing.
The Smallest Suitable Design
Memcached uses a shared-nothing architecture. The servers do not communicate with each other; the intelligence resides entirely in the client. To implement a scalable distributed cache, the client must use a consistent hashing algorithm (typically Ketama).
Core Components
- The Hash Ring: A logical circle representing the entire range of the hash function (e.g., 0 to 2^32-1).
- Virtual Nodes (vnodes): Instead of placing a server on the ring once, the client maps each physical server to multiple points (vnodes). This prevents "hotspots" where one server accidentally handles more traffic than others due to uneven key distribution.
- Client-Side Routing: The client hashes the key, finds the nearest server clockwise on the ring, and sends the request directly to that IP.
Trust and Data Boundaries
Because Memcached servers are passive data stores, the boundary of trust and logic is the Client Library. The server simply accepts a key and a value; it has no awareness of the rest of the cluster.
Data Loss Boundary: It is critical to understand that Memcached provides no native replication. If a node fails, the data on that node is gone. Consistent hashing mitigates the impact of this loss by ensuring only the keys assigned to that specific node are lost, rather than triggering a global cache miss.
Implementation Example
Most modern Memcached clients support consistent hashing via a configuration flag. Below is a conceptual configuration for a Python-based client (such as pymemcache or similar wrappers) using a consistent hashing distribution.
# Configuration for a distributed cluster
# Ensure the client library is configured for consistent hashing (Ketama)
servers = [
('cache-node-01.internal', 11211),
('cache-node-02.internal', 11211),
('cache-node-03.internal', 11211)
]
# The client should be initialized with a ConsistentHash distribution
# rather than a simple modulo distribution.
client = Client(
servers=servers,
use_consistent_hashing=True,
vnodes=160 # Standard number of virtual nodes to ensure even distribution
)
Operational Risks
- Configuration Drift: If different application servers have different lists of Memcached nodes in their config, they will hash keys to different servers, leading to a drastically lower hit rate.
- Memory Fragmentation: While consistent hashing handles the distribution, the Slab Allocator on the server handles the memory. If your object sizes vary wildly, you may see high eviction rates even if total memory seems available.
Operational Checks and Verification
To verify that consistent hashing is functioning correctly during a scale-out event, use the following diagnostic steps:
1. Baseline Metric Collection
Run the stats command on a node via telnet or netcat to establish a baseline of get_hits and evictions.
# Run on the Memcached server
echo "stats" | nc localhost 11211
2. The Node Removal Test
Remove one node from the client configuration. In a modulo system, the hit rate would drop toward 0%. In a consistent hashing system, the hit rate should only drop by approximately 1/N (where N is the number of nodes). Monitor the get_hits on the remaining nodes; they should see a slight increase in traffic as they absorb the orphaned keys.
3. Result Verification
Check the backend database latency. If the latency spikes significantly beyond the expected 1/N load increase, the client may be falling back to a non-consistent hashing method, causing a full cache invalidation.
Failure Modes and Design Changes
The consistent hashing design is sufficient for most read-heavy workloads, but certain conditions require a change in architecture:
| Condition | Failure Mode | Required Design Change |
|---|---|---|
| Strict Data Consistency | Node failure causes permanent data loss until DB refresh. | Introduce a caching layer with replication (e.g., Redis Cluster). |
| Extreme Key Skew | A single "celebrity key" overwhelms one node despite vnodes. | Implement client-side key splitting or a local L1 cache. |
| Dynamic Scaling | Updating config files across 100+ app servers is too slow. | Introduce a service discovery layer (e.g., Consul) to update server lists. |
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.