Skip to content
QSWEQB
hardDesignConceptMidSeniorStaff

How do you handle cache invalidation, and what goes wrong at scale?

Pick a write policy that matches your consistency requirement rather than treating invalidation as an afterthought, then defend against the three failure modes that only appear under load: stampede on expiry, staleness from lost invalidation messages, and unbounded growth from missing eviction.

3 min readUpdated 2026-07-26Asked at Amazon, Uber, Swiggy, Atlassian

What the interviewer is scoring

  • Whether you tie the invalidation strategy to a stated consistency requirement
  • Whether you name the thundering-herd problem before being prompted
  • Whether you acknowledge that cache-aside has an unavoidable race and can bound it
  • Whether you treat the cache as a failure domain with its own outage plan

Answer

Start from the consistency requirement

The interviewer is not looking for a list of patterns. They want to see you derive the strategy from a requirement, because "how stale can this data be" is a product question with a numeric answer, and every subsequent decision follows from it. A product catalogue tolerating five minutes of staleness and an account balance tolerating none are different systems.

Ask for that number, or state an assumption if the interviewer wants you to proceed. Everything below is a consequence of it.

The write policies

Cache-aside is the default and should be your baseline answer. The application reads from the cache, falls through to the database on a miss, and populates the cache. On write it updates the database and then deletes the key. Deleting rather than updating is deliberate: it avoids writing a value the next reader may not want and sidesteps ordering problems between concurrent writers.

Cache-aside has a genuine race that cannot be fully eliminated. A reader can miss, read the old value from the database, and be paused; a writer then updates the database and deletes the key; the reader resumes and writes its stale value into the cache, where it survives until the TTL. Acknowledging this rather than claiming cache-aside is correct is a strong signal. You bound the damage with a TTL, and you shrink the window with a short lock or by deleting the key a second time after a small delay.

Write-through updates the cache and the database synchronously, so the cache is never stale, at the cost of latency on every write and a cache that fills with data nobody reads. Write-behind acknowledges the write from the cache and persists asynchronously, which is fast but puts durability in the hands of the cache tier — acceptable for counters and view tallies, not for anything you cannot lose.

Event-driven invalidation publishes change events that consumers use to evict keys. This is what you reach for when the writer and the reader are different services, but it moves the problem: you now depend on delivery. A dropped event means indefinite staleness, so the TTL becomes your backstop rather than an optimisation.

The three failure modes that only appear at scale

Stampede, or thundering herd. A popular key expires and every concurrent request misses simultaneously, so the full read load lands on the database at once. This is the failure that most often takes a system down, and it is the one to raise unprompted. Three defences, usually combined: a short-lived lock so exactly one request recomputes while others briefly wait or serve stale; probabilistic early expiry, so instances refresh at slightly different times rather than all at the same instant; and jittered TTLs so keys written together do not expire together.

Staleness from lost invalidation. Every invalidation mechanism can fail — a dropped message, a network partition, a consumer crash between receiving and evicting. The design rule is that TTL is a correctness backstop and not merely a performance tuning knob, because it bounds how long any inconsistency can persist regardless of which mechanism failed.

Unbounded growth. Without an eviction policy a cache fills until it starts evicting unpredictably or the process is killed. Set a memory cap and an explicit policy, and know why you chose it: LRU for general access patterns, LFU when a small hot set dominates and you want to protect it from a scan, TTL-only when every entry has a natural lifetime.

Treat the cache as a failure domain

The question "what happens when the cache is down" separates candidates who have operated a cache from those who have only added one. If every miss falls through to the database, then a cache-tier restart converts a 95 percent hit rate into a 20-times traffic spike on the database, and the outage propagates. Concretely: a circuit breaker so a dead cache fails fast rather than adding its timeout to every request, load shedding or a request-coalescing layer so the database sees one query per key rather than thousands, and capacity headroom sized for some deliberate fraction of cold-cache traffic rather than for the steady-state hit rate.

The strongest version of this answer names a consistency target, picks one policy, and then spends most of its time on the failure modes. Candidates who list six patterns without choosing one read as having memorised a blog post.

Likely follow-ups

  • What happens to your system when the cache tier goes down entirely?
  • How would you invalidate a key that is derived from five upstream records?
  • Why is a very short TTL not a substitute for invalidation?
  • How would you detect that your cache is serving stale data in production?

Related questions

cachingconsistencyredisscalabilitystampede