Implementing Caching Patterns
1. Cache-Aside Pattern
| Step | Action |
| Read | App checks cache → miss → load from DB → populate cache → return |
| Write | App writes DB; invalidates cache (or updates) |
| Pros | Cache failures don't break reads (fall back to DB) |
| Cons | Stale data window; first read is slow |
Example: Cache-Aside (Java + Redis)
public Product get(String id) {
String cached = redis.get("prod:" + id);
if (cached != null) return mapper.readValue(cached, Product.class);
Product p = productRepo.findById(id).orElseThrow();
redis.setex("prod:" + id, 300, mapper.writeValueAsString(p));
return p;
}
2. Read-Through Cache Pattern
| Aspect | Detail |
| Mechanism | App reads cache only; cache loads from DB on miss |
| Cache Owns DB Access | Loader function configured at cache |
| Pros | Cleaner app code |
| Tools | Caffeine LoadingCache, Hazelcast, Ehcache |
3. Write-Through Cache Pattern
| Aspect | Detail |
| Mechanism | App writes cache; cache writes synchronously to DB |
| Pros | Cache always consistent with DB |
| Cons | Write latency = cache + DB |
4. Write-Behind Cache Pattern
| Aspect | Detail |
| Mechanism | App writes cache; cache async-batches writes to DB |
| Pros | Low write latency; coalesces writes |
| Cons | Data loss risk on cache crash; complex consistency |
5. Refresh-Ahead Cache Pattern
| Aspect | Detail |
| Mechanism | Async refresh entries before TTL expires (predicted access) |
| Benefit | Hides cache miss latency from users |
| Cost | Wasted refreshes for items not accessed again |
6. Distributed Cache Pattern
| Aspect | Detail |
| Mechanism | Centralized/sharded cache shared by service instances |
| Tools | Redis Cluster, Memcached, Hazelcast, Aerospike |
| Sharding | Consistent hashing across nodes |
| HA | Replication; sentinel/failover |
7. Near Cache Pattern
| Aspect | Detail |
| Definition | Local in-process cache + remote distributed cache (L1 + L2) |
| Lookup | Local first → remote → origin |
| Invalidation | Remote pubsub broadcasts invalidations |
| Pros | Sub-microsecond hits; reduces remote load |
8. Cache Invalidation Pattern
| Strategy | Detail |
| TTL Expiry | Eventually consistent; simplest |
| Explicit Invalidate | Delete key on write |
| Event-Driven | Subscribe to change events; invalidate |
| Versioned Keys | Bump version → old key naturally evicts |
| Tag-Based | Invalidate group by tag |
Warning: "There are only two hard things in CS: cache invalidation and naming things." Plan for stale data; design TTL conservatively.
9. Cache Stampede Prevention Pattern
| Strategy | Detail |
| Mutex / Singleflight | One thread loads; others wait/share result |
| Stale-While-Revalidate | Serve stale; refresh async |
| Probabilistic Early Expiry | Refresh with rising probability as TTL nears |
| Jittered TTL | Randomize expiry to avoid synchronized expiry |
10. Multi-Level Cache Pattern
| Tier | Storage | Latency |
| L1 | In-process (Caffeine) | ~ns |
| L2 | Local-machine (Redis sidecar) | ~µs |
| L3 | Distributed (Redis cluster) | ~ms |
| L4 | CDN edge | ~10ms (geo) |
| Origin | Database / service | ~10-100ms |