Caching is the most impactful performance optimization available. Understanding where to cache, what to cache, and when to invalidate separates high-performance applications from sluggish ones.
The Caching Hierarchy#
User Request
│
▼
┌───────────────┐
│ Browser Cache │ ← Fastest, most limited
└───────┬───────┘
│
┌───────▼───────┐
│ CDN Cache │ ← Fast, geographically distributed
└───────┬───────┘
│
┌───────▼───────┐
│ Application │ ← In-memory (Redis, Memcached)
│ Cache │
└───────┬───────┘
│
┌───────▼───────┐
│ Database │ ← Query cache, materialized views
│ Cache │
└───────────────┘
Browser Caching#
Cache-Control Headers#
Cache-Control Directives#
Directive │ Meaning
─────────────────┼─────────────────────────────────
public │ Can be cached by CDN/proxies
private │ Only browser can cache
no-cache │ Must revalidate before using
no-store │ Never cache
max-age=N │ Fresh for N seconds
immutable │ Never changes, skip revalidation
stale-while- │ Serve stale while fetching fresh
revalidate=N │
ETags and Conditional Requests#
CDN Caching#
Cache Keys#
Vary Header#
Cache Invalidation#
Application Caching#
Redis Caching Patterns#
Cache Stampede Prevention#
Stale-While-Revalidate#
Caching Strategies#
Cache-Aside (Lazy Loading)#
1. Check cache
2. If miss, load from database
3. Store in cache
4. Return data
Best for: Read-heavy workloads
Write-Through#
1. Write to cache
2. Write to database
3. Return success
Best for: Data that's read immediately after write
Write-Behind (Write-Back)#
1. Write to cache
2. Return success
3. Asynchronously write to database
Best for: Write-heavy workloads (with durability trade-off)
Refresh-Ahead#
1. Track cache expiration
2. Proactively refresh before expiry
3. Users always get cached data
Best for: Predictable access patterns
Query Caching#
Full Response Caching#
Entity Caching#
Invalidation Strategies#
Time-Based (TTL)#
Event-Based#
Tag-Based#
Monitoring#
Cache Metrics#
Conclusion#
Caching is powerful but requires careful consideration of consistency, invalidation, and monitoring. Start with simple strategies, measure hit rates, and evolve based on actual usage patterns.
Remember: the best cache is one you don't need. Before caching, consider if the underlying data source can be made faster. Cache judiciously—every cache introduces complexity and potential consistency issues.