Skip to content
About
Main content

Interview questions

Try each one before you open the answer.

What a cache is, and what it costs

1Why is a cache always potentially stale, even when it is working correctly?

A is a second copy of the data that can be read without asking the original, and nothing forces the two copies to agree. So staleness is the default, not a bug. It is bounded only by what you add on top: a time-to-live (), invalidation messages, or version numbers.

Read moreThe first copy with no obligation

2A cache serves 95% of reads. How dependent is the system on it?

Very. The store behind it now sees only 1 read in 20. This dependency, the cache's leverage, is , where h is the : at h = 95% it is 20 to 1. If the cache disappears, the store gets 20 times the load it normally sees, and it was probably sized for the normal load.

Read moreLeverage: how much do you depend on the cache?

3The hit rate falls from 99% to 98%. What happens to the database behind the cache?

Its load doubles. Misses go from 1% of reads to 2%, so at λ reads per second the database sees 0.02λ instead of 0.01λ. A one-point drop looks small on a dashboard and is a 2× change for the store.

Read moreLeverage: how much do you depend on the cache?

4When does caching a computed result pay for itself?

When each version of the result is read often enough to repay the cost of producing it. As an inequality, :

  • λ is reads per second and w is changes (new versions) per second, so λ / w is reads per version;
  • P is the cost of producing the entry, and S is what each hit saves.

If the data changes nearly as often as it is read, each entry is thrown away before it earns back P.

Read moreAmortization: does the cache pay?

5An object is read very heavily. Does that make it a good candidate for caching?

Not by itself. Volume does not decide; the ratio of reads to writes does, because it says how many reads each cached version serves before it changes. A heavily read object that changes on most reads gains nothing. A modestly read object that never changes is ideal.

Read moreAmortization: does the cache pay?

Hit rate, sizing and tiers

6What is reuse distance, and why does it predict cache hits better than the time since a key was last accessed?

is the number of distinct other keys accessed between two accesses to the same key. It is what matters because an entry is evicted when enough new, distinct items push it out, not when the clock moves. A key reused after an hour with nothing else touched in between still hits; a key reused after a second, with millions of distinct keys in between, misses.

Read moreReuse distance is the primitive, not time

7How can one trace of requests predict the hit rate of an LRU cache at every possible size?

By Mattson's result: under , an access hits if and only if its reuse distance is smaller than the cache size in entries. So one histogram of reuse distances gives the miss ratio at every size at once, the (). Sampling methods such as SHARDS make the histogram cheap to build from production traffic.

Read moreMattson's resultMeasuring it cheaply: SHARDS

8For which eviction policies can you not read the miss-ratio curve off a reuse-distance histogram?

For any policy that is not a , one where a bigger cache always holds everything a smaller one would. LRU is one. FIFO, CLOCK, random eviction and any policy with an are not, and caches with variable item sizes break the property too. For those, each cache size has to be simulated.

Read moreThe boundary condition: stack algorithms

9Key popularity is skewed. How does the amount of skew change the way a cache must grow as the data grows?

Popularity usually follows a with exponent α: the larger α, the more traffic goes to the top keys. Above α = 1, the cache size needed for a given hit rate stays about the same however large the data set becomes. At or below α = 1, a fixed-size cache loses hit rate as the data grows, silently, with no change to your code or configuration.

Read moreThe popularity exponent and the phase transition at α = 1

10Your cache has a 95% hit rate. Why can it not improve your p99 latency?

Because the slowest 5% of requests are the misses. Every above h, here above p95, is made only of misses, so p99 is a miss whatever the cache does. To improve the tail, make the miss path faster, hedge slow requests or shed load; a bigger cache does not help.

Read moreThe tail rule

11You can put a cache in front of the most requested service or in front of the slowest one. Which do you choose?

Usually the slowest. A cache is worth hit rate × (t_miss − t_hit): how often it hits, times the time each hit saves. Hits in front of a fast service save little, however many there are.

Read moreMiss penalty and the percentile you promised

12Why can a shared remote cache be slower than reading from a local SSD?

A remote cache hit costs a network round trip of about 0.3–1 ms. A read from a local NVMe SSD takes about 0.1 ms. So the remote "cache" is slower than the disk beside it, and a miss pays for both. A remote tier earns its place for other reasons: pooling capacity across servers, holding derived results, or surviving process restarts.

Read moreA distributed cache is not a latency tier

13Access to a million items follows a Zipf distribution. How much cache do you need for a 67% hit rate, and for 90%?

With N = 1,000,000, caching the top 1% gives about 67% of hits, and 90% needs about 25% of the data. The hit rate of the top k items is , so the benefit grows only with the logarithm of the cache size.

Read moreThe Zipf arithmetic

14A cache has a 90% hit rate, 0.1 ms per hit and 50 ms per miss. Where does the mean latency come from?

, and 98% of it comes from the misses. Hits and misses would contribute equally only at a 99.8% hit rate.

Read moreThe mean is not where you think

What to cache: results, metadata, views and absences

15You cache query results keyed by the query text. What else must go into the cache key?

Everything the result depends on that is not in the text: session settings, the user's identity and permissions, the (data version) the query read, and the values of volatile functions such as the current time. Leave any of these out and two users, or two moments, get each other's answers. Sometimes that is a security bug, not just a stale one.

Read moreWhat the key must contain

16Why is caching table metadata, such as schemas and file lists, such a good deal?

It has many readers, one dependency and rare changes: every query needs it, and it changes only when a write commits. In open the are , so they can be cached forever; only the pointer to the current snapshot needs a short TTL.

Read moreMetadata caching

17A semantic cache answers a new query from the cached results of different queries. What is its main weakness?

Deciding whether it has a hit. It must prove that the new query's answer is contained in what is cached (query containment), which is NP-complete in easy cases and undecidable in general. So practical are sound but incomplete, a partial hit can cost more than a plain miss, and the lookup gets slower as the cache grows.

Read moreSemantic caching

Freshness, invalidation and stampedes

19What are the ways to keep a cache close to the truth, and who pays for each?

There are three, and each is paid in a different currency:

  • Coordination (, invalidation broadcasts): the writer pays, with extra work on every write.
  • Staleness (TTLs, serving stale data): the reader pays, silently, by sometimes getting old data.
  • Verification (ETags, , ): the reader pays a round trip, but without the payload.

There is no fourth currency; every freshness scheme mixes these three.

Read moreThe three currencies of freshness

20Write-through, write-around and write-back are often presented as three settings of one dial. Why is that misleading?

They mix two independent decisions. One is write routing: where a write goes (the cache and the store, the store only, or the cache first). The other is freshness bounding: how the cache is kept close to the truth (not at all, TTL, versions, invalidation or leases). You choose both, and some combinations of the two are unsafe and must stay empty.

Read moreThe two dimensionsThe cells that must stay empty

21When should a write also go into the cache (write-through), and when should it skip the cache (write-around)?

Ask how likely the written key is to be read soon after the write. If the write predicts a read, such as a user's session, cart or own profile, write through so that the read hits. If it does not, as with event ingestion or bulk loads, write around, so that written keys do not push useful entries out of the cache.

Read moreWrite routing

22Why is write-back, acknowledging a write once it is in the cache, not a way to keep a cache fresh?

Because it changes what the cache is. The cache now holds the only copy of recent writes, so it becomes the source of truth: a crash can lose up to one flush interval of writes, evicting an entry depends on the store having accepted it, and flushing safely needs an ordered log. You have rebuilt durability inside the cache.

Read moreWrite routing

23On a write, why delete the cache entry instead of updating it with the new value?

Because nothing orders cache writes against store writes. If two updates race, the older value can reach the cache last and stay there indefinitely. A delete is idempotent: whatever the order, the next read misses and loads the current value.

Read moreWrite-invalidate versus write-update

24Your invalidation is correct and complete. Why do you still need a TTL?

Three things can still leave a wrong value in the cache:

  • a reader misses, reads the old value from the store, and writes it into the cache just after the writer's delete (a );
  • an invalidation message is lost;
  • a writer you do not know about changes the store directly.

A TTL is the floor that eventually corrects all three.

Read moreThe cells that must stay empty

25What does a TTL cost, and what can you use instead?

A TTL forces one miss per per period, even when nothing changed. One million hot keys with a 60-second TTL is about 16,700 forced misses per second, a cost that grows with the size of the cache, not with how often the data changes. Verification, such as an ETag with a conditional GET, instead asks whether the value changed, and pays for freshness with a round trip that carries no data.

Read moreFreshness bounding

26You put a version number in every cache key. How is that like MVCC in a database, and what does it cost?

The versions of a key form a version chain, entries for versions no one will read again are dead tuples, and eviction plays the part of vacuum. The cost is space: with V versions of each key alive, the useful capacity falls from C entries to about C / V. With popularity over N keys, that lowers the hit rate by about , a cost spread over every reader.

Read moreVersioned keys are MVCC

27How can users always see their own writes when they read through a cache that is not kept coherent?

Return a version token from the write and include it in the user's later reads: a cached entry older than that version counts as a miss. For monotonic reads, where a user never sees time go backwards, also refuse any version older than the newest one the user has already seen. Sending the user to the same server every time (sticky routing) is a weaker substitute.

Read moreSession guarantees come for free

28A hot cache key expires. How many duplicate recomputations reach the origin?

By , L = λ_k × W, where λ_k is the request rate for that key and W is how long one recomputation takes. At 1,000 requests per second and 2 seconds, that is 2,000 identical queries. Worse, the extra load slows the origin, so W grows and the feeds itself.

Read moreStampede

29Name three ways to prevent a cache stampede, and what each one costs.
  • Request coalescing: one request recomputes and the others wait for its result. It costs waiting.
  • Probabilistic early expiry: each request may refresh the entry shortly before it expires, with a probability that rises as expiry nears. It costs a little extra work and needs no coordination.
  • Serve-stale-while-revalidate: keep serving the old value while one request refreshes it. It costs freshness.

Also add random to every TTL, so entries filled at the same moment do not all expire at the same moment.

Read moreCoalescingProbabilistic early expiryServe-stale-while-revalidateCorrelated expiry

30You are bringing an empty cache into service. Why ramp traffic up instead of waiting a fixed time before sending it everything?

What has to be protected is the origin: the misses must stay within what it can absorb. So admit traffic at a rate λ(t) that keeps below the origin's capacity, where h(t) is the hit rate as the cache fills. A fixed timer ignores both the hit rate and the origin's spare capacity, so it is either needlessly slow or does not protect the origin at all.

Read moreWarming and prefetch

Eviction, admission and distribution

31Why can no eviction policy be optimal, and what follows from that?

Eviction is an online problem: the policy must choose without knowing future requests. For a cache of k entries, any deterministic policy can be made to miss k times as often as the best policy that knows the future, and LRU and FIFO both reach exactly that bound; randomized policies do no better than Θ(log k). So big improvements come from changing what reaches the cache rather than from cleverer eviction: hints, bypass, admission filters, and queries that declare they will not reuse what they read.

Read moreEviction has a proven limit

32Why is it cheaper to control what enters a cache (admission) than to choose what leaves it (eviction)?

Eviction needs exact metadata for every entry in the cache, and under LRU even a hit is a write to a shared list. Admission needs only an approximate popularity count, about ten bits per key in a count-min , with a small "" filter and periodic halving to forget old popularity, and it can run off the read path.

Read moreWhy eviction is expensiveWhy admission is cheap

33Why do distributed caches use consistent hashing, and what do virtual nodes add?

With hash(key) mod N, adding or removing one of N nodes moves of all keys, 90% at N = 10, so a membership change empties the cache and becomes an availability incident. moves only about K / N of K keys. , V positions on the ring for each server, even out the load, with the imbalance shrinking as ; 256 is a common choice.

Read moreWhy modulo hashing is dangerousVirtual nodes