Data building blocks
Cache failure modes
Caches also fail in three other ways. One key can get too much traffic, requests can ask for keys that don't exist, and an empty cache can send every read to the database. Each has a specific fix.
Beyond stampedes, a cache can break in three other ways. The load lands in the wrong place each time. One key overwhelms one node. Missing keys keep reaching the database. An empty cache sends every read to a database sized for a much higher hit rate. Each one has its own fix.
Concept
A Bloom filter is a compact set. It answers "definitely not in the set" or "maybe in the set." It can give false alarms, but it never misses a key that was added.
Hot keys
A hot key is one key that gets a large share of traffic. Say a celebrity's profile gets 200,000 reads per second. A single Redis process typically handles on the order of 100,000 to 200,000 simple operations per second, depending on payload size and pipelining. The node that owns the key hits its limit.
Three fixes:
- Local in-process cache for the hottest keys, with a TTL of 1 to 5 seconds. If 200 app servers each read the key once per second, Redis sees 200 requests per second, not 200,000.
- Key replication. Store copies such as
profile:42#0throughprofile:42#7on different nodes, and read one at random. Writes must update or delete every copy. - Read replicas for the Redis shard that holds the key.
Penetration
Cache penetration happens when requests ask for keys that don't exist. A cache never holds a missing key, so every request reaches the database. The cause can be a client bug looping on a deleted ID, or an attacker sending random IDs.
- Negative caching. Store "not found" with a short TTL, such as 30 seconds. Repeated requests for the missing ID stop reaching the database.
- A Bloom filter in front. Load every valid ID into the filter. A "definitely not present" answer skips the cache and the database.
Size of a filter: a 1% false-positive rate needs about 9.6 bits per element. For 100 million IDs, that's about 120 MB.
100,000,000 IDs × 9.6 bits = 960,000,000 bits ÷ 8 = 120,000,000 bytes ≈ 120 MBCold starts
After a deploy changes key formats, a cache flush, or a failover to an empty replica, the hit rate drops to 0%. The database gets the full read load. If it was sized for a 1% miss rate, it can fall over.
Mitigations:
- Warm the cache from a snapshot, or replay recent keys, before you take traffic.
- Roll out key-format changes gradually.
- Use Redis replication, so a failover keeps the data.
- Rate-limit misses, so the database slows down instead of collapsing.
Common mistakes
- Caching only the hits. Misses on missing keys stay expensive. Cache the "not found" answer too.
- Replicating hot keys without updating every copy. Stale copies persist until their TTL.
- Flushing the whole cache on deploy. You trigger a cold start on purpose. Change keys gradually.
Check yourself
- Why does local caching for a hot key cut Redis traffic so much? Each app server asks Redis once per TTL interval instead of once per request, so 200 servers send about 200 requests per second.
- Why cache "not found" results? So repeated requests for a missing ID stop reaching the database each time.
Key takeaways
- Hot keys need local caches, replicated copies or read replicas.
- Penetration needs negative caching, and a Bloom filter for large ID spaces.
- Cold starts need warm-up, gradual rollouts and rate-limited misses.
Further learning
The probabilistic data structures page explains Bloom filters and their relatives in more depth.
Next, read about the memcache case study, which shows how one large operator handled these problems.
Related
Caching
Where to put a cache, how to read and write through it, how to size it from hit-rate math, and how to keep it from serving stale data or melting down.
Cache stampede
When a hot key expires, every request misses at once and runs the same expensive query. Fix it by letting one request recompute, refreshing early, or serving slightly stale data.
Resilience patterns
The toolkit for keeping one failure from becoming an outage, from timeouts and retries to circuit breakers, bulkheads, load shedding and cells. Start here for the resilience map.