Multiple-choice synthesis across the caching unit: read/write strategies and their consistency, eviction and TTL, hit-ratio arithmetic, sharding with consistent hashing, the stampede, and the source-of-truth anti-pattern.
SDSenior◷ 13 min
Level
FoundationsJuniorMiddleSenior
Six questions that cut across the whole unit. Each is a decision you make when you add a cache, review a caching design, or debug one in production — not a definition to recite, but the consistency tradeoff, the hit-ratio arithmetic, and the failure modes that only appear at scale.
Confirm you can pick a read/write strategy by its consistency promise, choose an eviction policy and TTL, turn a hit-ratio change into DB load, shard a cache without nuking it, recognize and fix a stampede, and reject the cache-as-source-of-truth anti-pattern.
Quiz
Completed
You need the cache to never be stale relative to the database on writes, and write latency is not a concern. Which write strategy fits, and what is its cost?
Heads-up Write-back writes the cache now and flushes the DB LATER, so during the flush window the cache and DB disagree and a crash loses un-flushed writes. It's the least consistent, not the freshest. Synchronous freshness is write-through.
Heads-up Write-around skips the cache entirely on writes, so the cached value (if any) goes stale and the next read misses. It does the opposite of keeping the cache fresh. For never-stale-on-write you want write-through.
Heads-up Cache-aside is a READ-path pattern and doesn't watch the DB on writes, so it permits stale reads until a TTL/invalidation. The strategy that keeps the cache fresh on every write is write-through.
Quiz
Completed
A cache at its memory limit keeps evicting the homepage (read constantly, inserted at boot) while retaining a once-a-day report. Which eviction policy is configured, and what should it be?
Heads-up It's the reverse. LRU keeps recently-used items (the homepage would survive). Evicting a constantly-read but early-inserted key is FIFO's signature — fix it by switching TO LRU/LFU, not to FIFO.
Heads-up The pattern (always the early-inserted hot key) is FIFO, not random, and noeviction makes writes FAIL under pressure rather than evicting — wrong for a cache. Use LRU/LFU so access decides what stays.
Heads-up Size matters, but the specific symptom — evicting the hot key while keeping the cold one — is a policy bug (FIFO ignoring access). LRU/LFU would keep the homepage even at the same size by evicting the cold report instead.
Quiz
Completed
A cache fronting 100,000 reads/sec drops from a 99% to a 90% hit ratio after a deploy. By what factor does the read load on the database increase?
Heads-up The DB load scales with the MISS rate, not the hit rate. Misses go 1% → 10%, a 10× jump (1,000 → 10,000 reads/sec), even though the hit ratio only moved 9 points. That asymmetry is the whole danger.
Heads-up The 90% of hits are fine; it's the other 10% — now reaching the DB instead of 1% — that matters. That's 10× the previous miss volume on a DB sized for ~1% misses, which is why it melts down.
Heads-up Misses didn't double — they went from 1% to 10%, a 10× increase, not 2×. Compute the miss rate (100% − hit ratio) and the load factor: 10%/1% = 10×.
Quiz
Completed
You shard a cache and want adding or removing a node to disturb as little of the cache as possible. Which scheme, and why not the obvious one?
Heads-up Modulo spreads evenly but is catastrophic on topology change: when N changes, hash % N changes for ~all keys, so the entire cache remaps and misses at once. Consistent hashing limits the remap to ~1/N (one arc).
Heads-up Range partitioning helps locality but doesn't address the rescale problem and tends to create hot ranges. For a cache, you want consistent hashing so a node change moves only ~1/N keys instead of remapping everything.
Heads-up Replication is about survival, not key distribution — it doesn't decide which node owns a key. You still need a sharding scheme, and for a cache that scheme should be consistent hashing to bound rescale damage.
Quiz
Completed
A single hot key with a 60s TTL serves 50,000 RPS; every 60s the database is hit by a burst of thousands of identical queries. What is this, and the most direct fix?
Heads-up A longer TTL makes the stampede less frequent, not gone — it still detonates on each expiry. The structural fix is request coalescing (single-flight), which collapses N concurrent misses into one DB call.
Heads-up The spike is periodic at exactly the TTL boundary, which is the signature of a stampede on expiry, not memory-pressure eviction. Coalesce the concurrent recomputes; more memory doesn't address the synchronized miss.
Heads-up Nothing changed in the topology — the period matches the TTL, so it's a stampede when the hot key expires. Fix with single-flight (or probabilistic early recompute), not ring rebalancing.
Quiz
Completed
A design writes orders only to Redis, acknowledges the client, and flushes to Postgres asynchronously, reading Redis as the authoritative value. What's the core objection?
Heads-up Write-back is acceptable as a CACHE, but reading it as the AUTHORITATIVE value and ACKing before durability is the anti-pattern. Acknowledge only once the durable store has the write, and keep the cache droppable.
Heads-up Speed isn't the issue — Redis is fast. The issue is durability and authority: making a volatile cache the source of truth loses acknowledged data on a crash and leaves direct DB readers stale. Keep the DB authoritative.
Heads-up Throughput isn't the core objection; durability and consistency are. The cache-as-source-of-truth design loses data on an evict/crash and serves divergent values to DB readers. Write durably first, then cache.
Recall before you leave
01
Why does a 99%→90% hit-ratio drop melt the database?
02
Why shard a cache with consistent hashing instead of modulo, and how do you stop a hot-key stampede?
Recap
The through-line is that caching is a set of deliberate tradeoffs, not a switch you flip. A write strategy fixes a consistency promise: write-through is never-stale-on-write (two trips, churn), write-back is fastest but lossy and inconsistent during the flush, write-around skips the cache (first-read miss) — and the read-path cache-aside permits stale reads until a TTL/invalidation. Eviction must be access-aware (LRU/LFU, not FIFO, never noeviction for a cache), and TTL bounds staleness but must be jittered. The number that matters is the hit ratio, because the DB feels the miss rate: 99%→90% hits is a 10× DB load spike. Scaling out demands consistent hashing (only ~1/N keys move on rescale, vs modulo’s mass remap), survives node loss via replication (async, so slightly stale), and must defend the stampede with single-flight. And the deepest rule is that the cache is a disposable copy of an authoritative durable store — never the source of truth. Get these six decisions right and the cache makes reads fast without making the system fragile.
Something unclear?
Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.