Redis Cache Overload Kills Database
Redis saved our database. Until it killed it.
What happened:
- Traffic spike: 50K requests/second against a single Redis instance
- That rate alone wouldn't have hurt — Redis handles far more in simple GET/SET ops — but we were storing multi-hundred-KB serialized objects and running a few O(N) commands per request
- Redis hit 100% CPU; responses slowed from sub-millisecond to hundreds of milliseconds
- Client timeouts fired — and our cache client treated every timeout as a cache miss
- The full 50K requests/second fell through to the database as a thundering herd
- Database died within 30 seconds
Root cause:
Two compounding mistakes. We put expensive payloads on a single hot instance, and we had no circuit breaker: when Redis got slow, "timeout equals miss" meant we didn't degrade gracefully — we redirected the entire load onto the one system the cache existed to protect.
The fix:
- Circuit breaker pattern: if Redis is slow, serve stale data or fail the request — don't fall through to the database
- Distinguish timeouts from misses in the cache client; only true misses may query the database
- Redis Cluster for horizontal scaling; smaller values, no O(N) commands on hot paths
- Connection pooling with timeouts, and load shedding when approaching capacity
Capacity-testing the cache tier — not just the app tier — is a standard step in our DevOps and reliability engagements for exactly this reason.
Lesson: Your cache is not just a performance optimization. It's a critical component. When it fails, you need a plan that doesn't involve destroying your database.