Caching
"The purpose of a cache is to reduce the average time to access data."
Caching stores copies of data in temporary storage to serve future requests faster. It's the universal performance lever applied at every layer from CPU to continent.
Cache Fundamentals
Cache Hit vs Cache Miss
- Cache Hit: Requested data is found in cache
- Cache Miss: Data not found, must fetch from source
- Hit Ratio: Percentage of requests served from cache
Cache Locality
- Temporal locality: Recently accessed data likely to be accessed again
- Spatial locality: Data near recently accessed data likely to be accessed
Cache Eviction Policies
LRU (Least Recently Used)
Removes the least recently used items when cache is full.
Pros:
- Good temporal locality
- Widely implemented
- Predictable performance
Cons:
- Requires timestamp tracking
- Memory overhead
- Not optimal for all patterns
LFU (Least Frequently Used)
Removes items with lowest access frequency.
Pros:
- Good for stable access patterns
- Keeps popular items longer
- Better for read-heavy workloads
Cons:
- Complex implementation
- Memory overhead for counters
- Slow to adapt to changing patterns
FIFO (First In, First Out)
Removes items in insertion order.
Pros:
- Simple implementation
- Low overhead
- Predictable behavior
Cons:
- Ignores access patterns
- May remove frequently used items
- Poor temporal locality
Caching Layers
Browser Caching
Location: Client browser Content: Static assets, API responses Control: Cache-Control headers, ETags
Cache-Control: max-age=3600, public
ETag: "abc123"
CDN Caching
Location: Edge servers globally Content: Static assets, dynamic content Benefits: Reduced latency, geographic distribution
Application Caching
Location: Application memory Content: Computed results, database queries Technologies: Redis, Memcached, in-memory
Database Caching
Location: Database buffer pool Content: Query results, index pages Optimization: Buffer pool tuning, query cache
Cache Invalidation Strategies
Time-based Expiration
- TTL (Time To Live): Fixed expiration time
- Absolute expiration: Specific timestamp
- Sliding expiration: Reset on access
Event-based Invalidation
- Write-through: Update cache and database simultaneously
- Write-behind: Update cache immediately, database later
- Cache-aside: Application manages cache explicitly
Manual Invalidation
- Explicit cache clearing
- Tag-based invalidation
- Dependency tracking
Content Delivery Networks (CDNs)
CDN Types
- Pull-based: Content fetched on first request
- Push-based: Content pre-loaded to edge servers
CDN Benefits
- Reduced latency: Content closer to users
- Bandwidth savings: Offload from origin server
- Improved reliability: Distributed infrastructure
- DDoS protection: Absorb traffic spikes
Major CDN Providers
- Cloudflare: Security-focused, global network
- AWS CloudFront: AWS ecosystem integration
- Google Cloud CDN: Google infrastructure
- Fastly: Real-time configuration, edge computing
Caching Patterns
Cache-Aside (Lazy Loading)
- Application checks cache
- If miss, fetch from database
- Populate cache with data
- Return data to client
Pros:
- Simple implementation
- Cache only contains needed data
- Handles cache failures gracefully
Cons:
- Cache miss penalty
- Potential for stale data
- Thundering herd problem
Read-Through Cache
- Application always reads from cache
- Cache handles database fetch on miss
- Cache manages population and updates
Pros:
- Simplified application code
- Consistent cache behavior
- Better cache hit ratio
Cons:
- More complex cache implementation
- Cache becomes critical component
- Limited flexibility
Write-Through Cache
- Application writes to cache
- Cache immediately writes to database
- Returns success after both complete
Pros:
- Data consistency guaranteed
- No stale data in cache
- Simple recovery process
Cons:
- Higher write latency
- Increased database load
- Reduced write throughput
Write-Behind Cache
- Application writes to cache
- Cache acknowledges immediately
- Cache writes to database asynchronously
Pros:
- Low write latency
- High write throughput
- Can batch database writes
Cons:
- Risk of data loss
- Complex recovery logic
- Potential for inconsistency
Implementation Examples
Redis Caching
import redis
import json
r = redis.Redis(host='localhost', port=6379, db=0)
def get_user(user_id):
# Check cache first
cached_user = r.get(f'user:{user_id}')
if cached_user:
return json.loads(cached_user)
# Cache miss - fetch from database
user = db.get_user(user_id)
# Cache the result
r.setex(f'user:{user_id}', 3600, json.dumps(user))
return user
HTTP Caching Headers
# Strong caching
Cache-Control: public, max-age=31536000
# Validation-based caching
Cache-Control: no-cache
ETag: "abc123"
# No caching
Cache-Control: no-store, must-revalidate
Best Practices
Cache Key Design
- Descriptive names: Clear purpose identification
- Versioning: Handle schema changes
- Hierarchy: Organize related keys
- TTL strategy: Appropriate expiration times
Monitoring and Metrics
- Hit ratio: Measure cache effectiveness
- Eviction rate: Monitor cache pressure
- Response times: Track performance impact
- Memory usage: Prevent cache overflow
Common Pitfalls
- Cache stampede: Many simultaneous misses
- Stale data: Inconsistent cache state
- Memory leaks: Unbounded cache growth
- Single point of failure: Cache dependency
Key Takeaway: Effective caching requires understanding access patterns, choosing appropriate eviction policies, and implementing proper invalidation strategies across multiple system layers.