Skip to content

Caching — Core Concepts

Interview Relevance: Very High — Caching is the #1 tool for scaling reads. Know every layer, every policy, and every trade-off.

Caching stores copies of data in a faster storage layer so future requests for that data are served faster without hitting the origin (database or API).


The Cache Hierarchy — All 5 Layers


Layer 1 — Client-Side Cache (Browser)

How HTTP Cache Headers Work

Key Cache Headers

HeaderExampleMeaning
Cache-Control: max-age=8640086400 secondsCache for 24 hours
Cache-Control: no-cacheMust revalidate before serving
Cache-Control: no-storeNever cache (sensitive data)
Cache-Control: privateOnly browser can cache (not CDN)
Cache-Control: publicCDN and browser can both cache
ETag: "abc123"Hash of contentUsed for conditional requests (304)
Last-Modified: Mon, 01 Jan 2025TimestampAlternative to ETag

Layer 2 — CDN Cache

What to cache on CDN:

  • ✅ Static assets (JS, CSS, images, fonts)
  • ✅ Public API responses (product listings, news feeds)
  • ✅ Video/audio streams
  • ❌ Authenticated user data (use Cache-Control: private)
  • ❌ Real-time or frequently updated data

Layer 4 — Application Cache (Redis & Memcached)

This is the layer most discussed in FAANG interviews.

Redis vs. Memcached

FeatureRedisMemcached
Data structuresString, Hash, List, Set, Sorted Set, StreamString only
Persistence✅ RDB snapshots + AOF log❌ In-memory only
Replication✅ Master-replica + Sentinel❌ No native replication
Clustering✅ Redis Cluster (hash slots)✅ Client-side sharding
Pub/Sub✅ Built-in❌ No
Atomic operations✅ INCR, LPUSH, ZADDLimited
Memory efficiencySlightly higher overhead✅ Slightly more efficient
Use caseLeaderboards, sessions, queues, rate limitingSimple key-value cache only

Interview answer: "I'd default to Redis in almost every case — the richer data structures, persistence, and native clustering make it far more versatile than Memcached."


Cache Eviction Policies

When the cache is full, the eviction policy decides which item to remove.

LRU in Action — Step by Step

Cache capacity: 3 slots

Request sequence: A, B, C, A, D

Step 1: GET A → MISS → Cache: [A]
Step 2: GET B → MISS → Cache: [B, A]
Step 3: GET C → MISS → Cache: [C, B, A]
Step 4: GET A → HIT  → Cache: [A, C, B]  ← A moved to front (recently used)
Step 5: GET D → MISS → Cache full!
                        EVICT B (least recently used, at the tail)
                        Cache: [D, A, C]

LRU vs LFU — Which to Use?

ScenarioBest PolicyReason
URL Shortener redirectsLRURecent URLs are likely still hot
Trending productsLFUMost popular products should stay cached
Session dataTTLSessions have a natural expiry time
News feedLRURecent content is what users want
Music streamingLFUPopular songs accessed millions of times
Rate limiting countersTTLCounters reset after a time window

All Redis Eviction Policies

PolicyEvictsBest For
allkeys-lruLRU across all keysGeneral-purpose cache
volatile-lruLRU among keys with TTL onlyMix of cache + persistent data
allkeys-lfuLFU across all keysFrequency-based (trending content)
allkeys-randomRandom keyWhen access pattern is uniform
volatile-ttlKey with shortest TTL firstPrioritize expiring data
noeviction❌ Returns error when fullWhen data loss is unacceptable

Cache Invalidation Strategies

"There are only two hard things in Computer Science: cache invalidation and naming things." — Phil Karlton

Strategy 1 — Cache-Aside (Lazy Loading) ⭐ Most Common

The application manages the cache explicitly. On a miss, it loads from DB and populates the cache.

✅ Cache only what's actually needed (lazy)
✅ Cache failures don't break the app (fallback to DB)
✅ Simple to implement
❌ Cache miss on first request (cold start)
❌ Potential stale data between write and invalidation (race condition)

Strategy 2 — Write-Through

Every write goes through the cache synchronously before returning success.

✅ Cache is always consistent with the database
✅ No stale reads
❌ Write latency = cache write + DB write
❌ Cache fills with data that may never be read (write-heavy apps waste memory)

Strategy 3 — Write-Behind (Write-Back)

Writes go to cache immediately; the cache asynchronously flushes to the database.

✅ Extremely fast writes (returns before DB write)
✅ Batching reduces DB write pressure
❌ Risk of data loss if cache crashes before flushing
❌ Complex to implement correctly
❌ Not suitable for financial transactions

Strategy 4 — Refresh-Ahead (Proactive Refresh)

The cache predicts which keys will expire soon and pre-fetches them before they go stale.

✅ Zero cache misses for hot data (best user experience)
✅ Smooth for predictable access patterns
❌ May prefetch data that's never accessed (wasted DB load)
❌ Complex implementation

Strategy Comparison

StrategyWrite LatencyRead LatencyConsistencyComplexityBest For
Cache-AsideLowHigh on missEventualLowGeneral read-heavy apps
Write-ThroughHigh (synchronous)LowStrongMediumRead-heavy, write-rare
Write-BehindVery LowLowEventualHighWrite-heavy, loss-tolerant
Refresh-AheadN/AVery LowNear-real-timeHighPredictable hot data

Cache Pitfalls & Solutions

Pitfall 1 — Cache Stampede (Thundering Herd)

Pitfall 2 — Cache Penetration

Requests for non-existent keys bypass the cache and hammer the DB every time.

Pitfall 3 — Cache Avalanche

Many cache keys expire at the same time, causing a sudden spike of DB queries.

❌ Problem:
  All product pages cached with TTL=3600s at midnight
  At 1:00 AM, all 100,000 keys expire simultaneously
  → 100,000 DB queries hit at once → DB crashes

✅ Fix: TTL Jitter
  Instead of TTL = 3600
  Use TTL = 3600 + random(0, 600)  ← adds up to 10min of jitter
  Keys now expire spread across a 10-minute window
  → DB load smoothed out ✅

Worked Example — Caching in the URL Shortener

Cache decisions for the URL Shortener:

DecisionChoiceReason
Cache strategyCache-AsideSimple, lazy-loads only accessed URLs
Eviction policyallkeys-lru + TTLRecent URLs are hot; TTL mirrors URL expiry
InvalidationDEL on URL update/deleteImmediately removes stale entry
Stampede protectionRedis SETNX mutex lockPrevents duplicate DB fetches on popular expiries
Penetration protectionReturn 404 and cache null for 60sPrevents DB hits for invalid short codes
TTL jitterexpiry ± random(0, 300s)Prevents mass expiry of URLs created in bulk

Interview Cheat Sheet

One-Line Summaries

Cache-Aside:    App checks cache → on MISS load DB → populate cache
Write-Through:  Every write → cache + DB synchronously
Write-Behind:   Write to cache only → async flush to DB later
Refresh-Ahead:  Pre-fetch hot keys before they expire

LRU: Evict the least recently accessed item
LFU: Evict the least frequently accessed item
TTL: Evict after a fixed time window

Stampede:    Many simultaneous misses → fix with mutex lock
Penetration: Non-existent keys bypass cache → fix with Bloom Filter
Avalanche:   Mass simultaneous expiry → fix with TTL jitter

The Interview Phrase

"For this read-heavy system, I'd use Cache-Aside with Redis in front
 of the database. The eviction policy would be allkeys-lru since recency
 predicts access probability. I'd add TTL jitter of ±10% to prevent
 cache avalanche, and a Redis SETNX mutex to handle cache stampede on
 popular key expiry. For cache penetration, I'd cache null results for
 60 seconds and optionally add a Bloom Filter at the app layer."

Red Flags vs. Green Flags

🔴 Red Flag🟢 Green Flag
"Just add Redis" with no further detailSpecify strategy, eviction policy, TTL, and invalidation
Ignore cache invalidationAddress it explicitly — it's the hardest problem
Use Write-Through for write-heavy appsMatch strategy to workload (Write-Behind for writes)
Forget cache stampede / avalancheAlways mention TTL jitter and mutex lock
Cache authenticated user data on CDNCDN only for Cache-Control: public responses
Treat Redis and Memcached as identicalKnow Redis's richer features and when each fits

IMPORTANT

Cache invalidation is the hardest problem in caching. Always address it explicitly. Say: "When a URL is updated or deleted, I immediately DEL the cache key so the next read fetches fresh data from the DB."

TIP

Mentioning cache stampede, cache penetration, and cache avalanche — and their mitigations — is a strong senior signal. Most candidates only talk about hit rate and eviction policies.

Released under the ISC License.