Question #59 of 60•Scaling•Hard• ~3 min read

How do you eliminate the Thundering Herd / Cache Stampede problem under massive concurrent load?

Executive Takeaway

Analyze cache stampedes when hot keys expire: Mutual Exclusion (Mutex/Redlock), Probabilistic Early Expiration (XFetch algorithm), stale-while-revalidate, and request singleflighting.

Architectural Breakdown & AnalysisFAANG Aligned

The Cache Stampede (Thundering Herd) is one of the most dangerous outage patterns in high-concurrency systems. When a viral, highly accessed cache key (e.g., the homepage catalog or election results) reaches its TTL and expires, thousands of concurrent requests encounter a Cache Miss simultaneously.\n\nAll concurrent requests immediately hammer the downstream database with identical expensive queries, saturating database connections, spiking CPU to 100%, and knocking the entire service offline.\n\n---\n\n## 1. Solution 1: Mutual Exclusion Locking (Distributed Mutex)\nOnly the first request that discovers the cache miss is allowed to query the database and rebuild the cache. All other callers wait or retry:\n\npython\n# DISTRIBUTED MUTEX USING REDIS SETNX\nvalue = redis.get("hot_key")\nif value is None:\n # Acquire short 5-second lease lock\n if redis.set("lock:hot_key", "1", nx=True, ex=5):\n try:\n value = db.query_expensive_data()\n redis.set("hot_key", value, ex=3600)\n finally:\n redis.delete("lock:hot_key")\n else:\n # Another worker is refreshing; sleep 50ms and retry from cache\n time.sleep(0.05)\n return get_with_lock("hot_key")\n\n\n---\n\n## 2. Solution 2: Probabilistic Early Expiration (The XFetch Algorithm)\nRather than waiting for the key to hard-expire, background readers calculate a probability of refreshing the key before it expires based on compute cost $\beta$ and remaining TTL:\n$$\Delta - \beta \times \delta \times \ln(\text{random}()) > \text{TTL}$$\n* As the key approaches expiration, the probability of an incoming reader proactively triggering a background database refresh increases.\n* Mathematical Guarantee: Exactly one worker refreshes the cache before expiration without distributed locks!\n\n---\n## 3. Solution 3: Stale-While-Revalidate (Background Worker)\n* Set two timestamps in the cache item: expiry and stale_after.\n* When a request arrives between stale_after and expiry:\n 1. The server immediately returns the stale data to the user (<2ms latency).\n 2. The server dispatches an asynchronous background task to reload fresh data from the database and update the cache.\n* Users never experience cache miss latency, and the database never receives burst queries.\n\n### Key Architectural Comparison\n| Stampede Defense | Implementation Complexity | Latency Impact during Expiry | DB Load Protection | Best Fit |

:---:---:---:---:---
XFetch (Probabilistic)Moderate (Math formula)Zero (Refreshed in advance)OptimalHigh-traffic e-commerce catalogs
Stale-While-RevalidateLowZero (Returns cached stale data)100%News feeds, homepages, CDN edges

| Never Expire (Async Cron) | High (Operational overhead) | Zero | 100% | Static reference data, sitewide configs |\n

Previous QuestionHow do you design an elastic search-as-you-type autocomplete system (Tries vs. Inverted Indexes)?Next Question How do you design a real-time distributed leader election mechanism using Apache ZooKeeper or etcd?

Continue Learning on Being SDE

Explore deep-dive system architecture modules, low-level object-oriented designs, and interview cheat sheets.