Skip to main content

Caching Strategies

TL;DR

Caching = Store frequently accessed data in fast storage (RAM) to avoid slow database queries. Cache is the #1 way to improve performance - can make system 10-100x faster.

Core Concepts

Cache Hit vs Miss

  • Cache hit: Data in cache (fast, ~1ms)
  • Cache miss: Query database (~100ms), then store in cache
  • Performance gain: 100x faster (1ms vs 100ms)

Caching Strategies

Cache-Aside (Lazy Loading) - Most Common

def get_user(user_id):
# 1. Try cache first
cached_user = cache.get(f"user:{user_id}")
if cached_user:
return cached_user # Cache hit

# 2. Cache miss - query database
user = db.query("SELECT * FROM users WHERE id = ?", user_id)

# 3. Store in cache (TTL = 5 minutes)
cache.set(f"user:{user_id}", user, ttl=300)
return user

Write-Through Cache

Write to cache and database simultaneously.

  • ✅ Cache always consistent with DB
  • ❌ Slower writes (two operations)

Write-Behind (Write-Back)

Write to cache immediately, async write to database.

  • ✅ Fast writes
  • ❌ Risk of data loss if cache crashes

Cache Eviction Policies

PolicyEvictUse Case
LRULeast recently usedGeneral purpose (most common)
LFULeast frequently usedHot data stays (trending videos)
TTLExpired itemsGuaranteed freshness

Cache Stampede Solutions

# Locking solution
def get_cached(key):
data = cache.get(key)
if data:
return data

if cache.set_nx(f"lock:{key}", 1, ttl=10): # Acquire lock
data = db.query(key)
cache.set(key, data, ttl=300)
cache.delete(f"lock:{key}")
return data
else:
time.sleep(0.1)
return get_cached(key) # Retry

TTL Guidelines

Data TypeTTL
ImmutableNo TTL (forever)
Static content1 year
User profiles1 hour
Product prices5 minutes
Real-time data10 seconds or don't cache

Quick Reference

Strategies: Cache-aside (lazy), Write-through (sync), Write-behind (async), TTL (expiry)

Eviction: LRU (default), LFU (hot data), TTL (freshness)

Layers: Browser → CDN → App (in-memory) → Redis → Database