Interview Q&A · 45 questions · 12 answered publicly
Caching Interview Questions
Ordered by how often they're asked. Sign in free to see every answer, rate your confidence and run timed mock interviews.
-
Most asked Explain the main caching patterns: cache-aside, read-through, write-through and write-behind.
Summary
Cache-aside: the application reads the cache, and on a miss loads from the database and populates the cache. Read-through: the cache itself loads missing data. Write-through: writes go to the cache and the store synchronously. Write-behind: writes go to the cache and are flushed to the store asynchronously.
Longer Answer
Cache-aside is the most common (Redis + app code) because it's simple and the cache only holds requested data; the app invalidates or updates the key on writes. Write-through keeps cache and store consistent at the cost of write latency. Write-behind gives fast writes but risks data loss if the cache fails before flushing, so it's used for counters or analytics, not money.
Code Example
def get_product(product_id: int) -> dict: key = f"product:v2:{product_id}" if (cached := redis.get(key)) is not None: return json.loads(cached) product = db.fetch_product(product_id) # miss → source of truth redis.set(key, json.dumps(product), ex=300) # populate with TTL return product def update_product(product_id: int, data: dict) -> None: db.update_product(product_id, data) redis.delete(f"product:v2:{product_id}") # invalidate after the writeKey Points
- Cache-aside: app-managed, most common
- Read-through: cache loads on miss
- Write-through: synchronous dual write
- Write-behind: async, risk of loss
Comparison / Tradeoffs
Pattern Consistency Write latency Typical use Cache-aside Eventual (invalidate) Low General reads Write-through Strong-ish Higher Read-after-write needs Write-behind Weak Lowest Counters, analytics -
Most asked Why is cache invalidation hard, and what strategies help?
Summary
Invalidation is hard because data changes in many places, caches are distributed, and races between reads and writes can repopulate stale values. Strategies: TTLs as a safety net, delete-on-write, versioned keys, event-driven invalidation, and accepting bounded staleness where the business allows.
Longer Answer
A classic race: request A misses and reads the old value from the DB; request B updates the DB and deletes the key; request A then writes the stale value into the cache. Mitigations include short TTLs, delayed double delete, versioned keys (bump
product:v{n}), or write-through with compare-and-set. Decide per data type how stale is acceptable.Key Points
- TTL as safety net
- Delete on write
- Versioned keys
- Events for cross-service invalidation
- Define acceptable staleness
-
Most asked What is a cache stampede (thundering herd) and how do you prevent it?
Summary
A stampede happens when a popular key expires and many concurrent requests miss at once, all hitting the database to recompute the same value, which can overload it. Prevent it with request coalescing/locks, early (probabilistic) recomputation, stale-while-revalidate, and jittered TTLs.
Longer Answer
Options: (1) a short lock (
SET key:lock NX EX 5) so only one request recomputes while others wait or serve stale; (2) refresh before expiry with probability increasing as expiry nears (XFetch); (3) serve the stale value while one background task refreshes; (4) add random jitter to TTLs so many keys don't expire together.Key Points
- Many misses on one hot key
- Single-flight locks
- Early/probabilistic refresh
- Stale-while-revalidate
- TTL jitter
-
Most asked How does HTTP caching work (Cache-Control, ETag, CDNs)?
Summary
Cache-Controltells browsers and CDNs whether and how long to cache (public, max-age=300,private,no-store,s-maxage,stale-while-revalidate); validators (ETag,Last-Modified) let clients revalidate with conditional requests and receive304 Not Modified; CDNs cache responses at edge locations close to users.Longer Answer
Static assets with hashed filenames can be cached for a year with
immutable. API responses that are personalized must beprivateorno-store.Varytells caches which request headers change the response (e.g.,Accept-Encoding). Purge or use short TTLs plus surrogate keys for content that changes.Code Example
# Static, fingerprinted asset Cache-Control: public, max-age=31536000, immutable # Public API response, revalidate in the background Cache-Control: public, max-age=60, stale-while-revalidate=300 ETag: "v42-9f8e" # Personalized response Cache-Control: private, no-storeKey Points
- Cache-Control directives
- ETag/Last-Modified + 304
- CDN edge caching
- private/no-store for personalized data
- Vary header
-
Most asked Explain the difference between cache penetration, cache breakdown and cache avalanche.
Summary
Penetration: requests for data that doesn't exist bypass the cache every time. Breakdown (stampede): one hot key expires and many requests rebuild it at once. Avalanche: many keys (or the whole cache) disappear at once and the database takes all the load.
Longer Answer
Fixes differ: negative caching and Bloom filters for penetration; request coalescing, locks, early refresh or stale-while-revalidate for breakdown; TTL jitter, bounded database fallback, replication/persistence and warming for avalanches.
Key Points
- Penetration: missing keys
- Breakdown: one hot key expires
- Avalanche: mass loss/expiry
- Different protections for each
Deep dive: Database Caching at Scale
-
Most asked In cache-aside, why can a value be stale even though you delete the key on every write?
Summary
The stale-set race: a reader misses and reads the old row, a writer commits and deletes, then the reader sets the old value — which stays until the TTL. Leases or version-checked sets prevent it; short TTLs bound it.
Longer Answer
Facebook's memcache paper introduced leases for exactly this ('stale sets') and for thundering herds. In Redis, store a version with each value and set only if newer in a Lua script.
Key Points
- Reader set lands after the delete
- Leases / versioned sets
- Short TTLs as a bound
Deep dive: Database Caching at Scale
-
Most asked How can a CDN leak one user's data to another, and how do you prevent it?
Summary
If a personalized response lacks
Cache-Control: private, no-store(or the CDN ignores origin headers), the shared cache stores it by URL and serves it to the next visitor. Mark personalized responses private, make the CDN respect headers, and don't cache responses with Set-Cookie/Authorization.Longer Answer
Split pages into a shared, cacheable shell and client-loaded personalized parts; add automated checks that authenticated endpoints return private/no-store.
Key Points
- Shared caches key by URL
- private, no-store for personal data
- CDN must respect origin headers
Deep dive: Database Caching at Scale
-
Most asked How do you design good cache keys?
Summary
Keys should be deterministic, namespaced, versioned and include every input that changes the result (tenant, locale, user/role when personalized, query parameters), while staying reasonably short.
Longer Answer
Example:
catalog:v3:tenant:42:product:1001:locale:en. Versioning lets you change the cached format without collisions. Hash long inputs (search queries). Forgetting an input (like tenant or permissions) causes data leaks between users.Key Points
- Namespace + version
- Include every varying input
- Hash long inputs
- Missing tenant/user = data leak
-
Most asked What are the risks of caching personalized or authorized data?
Summary
If cache keys or HTTP caching rules don't include the user, tenant or permissions, one user's data can be served to another, a serious data leak. CDNs caching authenticated responses are a common source of such incidents.
Longer Answer
Mark personalized responses
Cache-Control: privateorno-store, include tenant/user in application cache keys, and test cache behavior with multiple users.Key Points
- Keys must include identity
- private/no-store for user data
- Beware CDNs on authenticated routes
- Test with multiple users
-
Most asked In a system design interview, how do you decide what and where to cache?
Summary
Identify read-heavy, expensive or latency-sensitive paths and their staleness tolerance; pick the closest safe layer (CDN for public content, Redis for shared computed data, local cache for config); define keys, TTLs, invalidation and stampede protection; and estimate hit ratio, memory size and the load the database must still handle.
Longer Answer
State failure behavior (cache down), consistency guarantees (eventual, read-your-writes) and how you'd monitor effectiveness.
Key Points
- Target hot, expensive reads
- Choose the layer by audience
- Keys, TTLs, invalidation
- Capacity and failure plans
-
Most asked Should you invalidate the cache before or after the database commit?
Summary
After. Deleting before commit lets other readers re-cache the old row (they still see it until the commit). Use on-commit hooks or transactional events.
Longer Answer
Django
transaction.on_commit, LaravelDB::afterCommit, Spring@TransactionalEventListener(AFTER_COMMIT)or a transaction-aware cache manager. Also avoid filling the cache from a lagging replica right after a write.Key Points
- Invalidate after commit
- Before-commit deletes get undone
- Don't fill from lagging replicas
Deep dive: Database Caching at Scale
-
Most asked How does stale-while-revalidate work, and when is it inappropriate?
Summary
After a soft expiry, the cache keeps serving the old value while one background refresh rebuilds it, avoiding stampedes and latency spikes. It's inappropriate for data that must be exactly current, like stock at checkout or permissions.
Longer Answer
Available in HTTP (
Cache-Control: stale-while-revalidate), in libraries (CaffeinerefreshAfterWrite, LaravelCache::flexible) and easy to build with a soft-expiry timestamp inside the value.Key Points
- Serve stale, refresh once
- Prevents stampedes
- Not for must-be-fresh data
Deep dive: Database Caching at Scale
- Redis vs Memcached: when would you choose each?
- What are cache eviction policies (LRU, LFU, TTL) and how do you choose?
- What are the different layers where you can cache in a web system?
- When should you use an in-process (local) cache vs a distributed cache?
- How do you handle hot keys in a distributed cache?
- How do you keep cache and database consistent on writes?
- How does Redis scale and stay available?
- When would you use materialized views or denormalization instead of a cache?
- What happens if the cache goes down, and how do you design for it?
- Your Redis cluster has one shard at 100% CPU while others idle. What's likely and how do you fix it?
- How do you keep in-process L1 caches on many pods consistent?
- What are the risks of write-behind caching?
- What must a cache key include for an API response in a multi-tenant app?
- Why can a Redis failover bring back deleted (stale) cache entries?
- How do you invalidate caches when many services and scripts write to the same tables?
- What is negative caching and why is it useful?
- How do you choose a TTL?
- What is cache warming and when is it needed?
- What should you consider when serializing objects into a cache?
- Which metrics show whether a cache is working well?
- How do you invalidate content on a CDN?
- How would you cache high-frequency counters (views, likes) efficiently?
- Why are database query caches often disabled or removed?
- What's the difference between memoization and caching?
- How do you implement a distributed lock with Redis, and what are the caveats?
- How do you cache GraphQL or highly dynamic API responses?
- How do frontend applications cache server data?
- How does a Bloom filter help in caching systems?
- Is it OK to store sessions in Redis?
- How do you invalidate thousands of related cache keys (e.g. all pages of a category) efficiently?
- Why add jitter to cache TTLs?
- Which Redis maxmemory-policy should a pure cache use, and what if sessions share the instance?
- What metrics tell you a cache is healthy?