Caching Strategies
Cache-Aside (Lazy Loading)
App checks cache first. On miss, reads from DB and writes to cache. Most common pattern. Risk: cache miss penalty + stale data until TTL expires.
Read-Through
Cache sits in front of DB. On miss, cache itself fetches from DB and stores it. App only talks to cache. Simplifies app code but couples cache to DB.
Write-Through
Every write goes to cache AND DB synchronously. Guarantees cache is always fresh. Downside: higher write latency (two writes per operation).
Write-Behind (Write-Back)
Write to cache immediately, async flush to DB in batches. Very fast writes. Risk: data loss if cache crashes before flush. Used in CPU caches, disk controllers.
Refresh-Ahead
Proactively refreshes cache entries before they expire, based on access patterns. Reduces miss rate for hot keys. Adds complexity and background work.
Cache Invalidation
The hardest problem. TTL-based (simple, eventual consistency), event-based (publish on write), version-based (etag/hash comparison).
Cache Stampede
Many requests hit cache miss simultaneously → all query DB at once. Solutions: lock/mutex, probabilistic early expiry, pre-warming.
Eviction Policies
LRU (least recently used) — most common. LFU (least frequently used) — good for skewed access. FIFO — simplest. Random — surprisingly decent.
Cache Levels
L1: in-process (HashMap) ~1μs. L2: local Redis/Memcached ~1ms. L3: distributed cache ~5ms. L4: CDN edge ~50ms. Each level trades freshness for speed.
When to Cache
High read-to-write ratio. Expensive computations. Tolerance for eventual consistency. Hot data that fits in memory. Don't cache: frequently changing data, security-sensitive data.