Tags: caching, redis, memcached, cdn, cache-aside, write-through, system-design
Level: intermediate
TL;DR: Guide to common caching patterns, eviction policies, and cache invalidation strategies for scalable backend systems.
Cache-Aside (Lazy Loading): application checks cache first, queries DB on miss, writes result back to cache.
Read-Through: application queries cache abstraction; cache fetches from DB on miss transparently.
Write-Through: data is written to cache and DB synchronously, ensuring consistency but higher write latency.
Write-Back (Write-Behind): data written to cache immediately, DB updated asynchronously in batches.
Write-Around: data written directly to DB, bypassing cache to avoid cache pollution for rarely read data.
Eviction policies define removal rules when memory limits are reached (LRU, LFU, FIFO, TTL).
Cache invalidation options: explicit key deletion on update, time-to-live expiration, or event-driven triggers.
Cache layers span multiple tiers: browser/client, CDN edge, API gateway, application memory, distributed stores.
Q: How do you handle cache invalidation in a high-traffic microservices architecture?R: I rely on event-driven invalidation via message brokers on DB updates, paired with defensive TTLs to guarantee convergence and prevent stale state.
Q: What is the difference between Cache-Aside and Write-Through?R: In Cache-Aside, the application manages reads and writes directly between cache and DB; in Write-Through, the cache layer itself handles DB writes synchronously.
Q: How do you protect against cache stampede (thundering herd)?R: I use mutex/distributed locks around DB recomputation, background pre-fetching with early TTL revalidation, or stale-while-revalidate patterns.
Cache stampede when popular keys expire simultaneously under high read concurrency.
Cache penetration: requests for non-existent keys repeatedly hitting the database; solve with bloom filters or caching null objects.
Cache breakdown: high-traffic hot key expires suddenly, saturating DB; solve with mutex locking or probabilistic early expiration.
Memory exhaustion due to missing TTLs and unbounded key growth.
Inconsistent data caused by race conditions between concurrent DB updates and cache writes.
// Cache-Aside pattern implementation
async function getCachedUser(userId: string): Promise<User> {
const cacheKey = `user:${userId}`;
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
const user = await db.users.findById(userId);
if (user) {
await redis.set(cacheKey, JSON.stringify(user), 'EX', 3600);
}
return user;
}
Bash
# Redis CLI inspection & eviction diagnostics
redis-cli INFO stats | grep -E 'keyspace_(hits|misses)'
redis-cli --bigkeys
redis-cli CONFIG GET maxmemory-policy
[ ] Implement Redis distributed lock for hot key cache repopulation
[ ] Configure bloom filters for cache penetration prevention
[x] Cache-Aside vs Write-Through trade-offs
[x] Eviction policies (LRU, LFU, TTL)
Redis Documentation: Memory Optimization and Eviction Policies
System Design Interview – Alex Xu (Chapter: Caching & Scalability)