System Design · Module 6 · Lesson 1 of 4 · 40 min
Cache Placement Read Paths and Write Strategies
Choose where a cache belongs, trace cache-aside, and compare read-through write-through write-back and write-around responsibilities.
01 The idea
The problem this lesson solves
A cache stores a reusable result so the system can avoid repeating more expensive work. That sounds simple until the original value changes, the cached value disappears or the cache becomes unavailable. The first design decision is therefore not “which cache product?” It is which result may be reused, who owns the truth, and how reads and writes move between those copies.
You should recognize the application, the database and the request path. Treat the database as the authority unless explicitly stated otherwise.
02 Worked example
Branch on a cache hit or miss
03 The method
Understand the mechanism
Choose the cache boundary and authority
For a short-link lookup, the database owns code a7’s destination and the cache stores a permitted copy. Losing the cache should cause extra reads, not loss of the only accepted mapping. This relationship differs from using a memory store as the authoritative database.
Caches can live in the browser, at an edge, inside an app process or in a shared service. A local cache avoids a network hop but each app has its own copies and memory budget. A shared cache centralizes more reuse but introduces network latency and a shared dependency.
Choose what is cached: a database object, a query result, an authorization decision or an HTTP representation. Each has different keys and invalidation requirements. Caching a whole user-specific response under only a public path can expose one user’s data to another.
A key should include every dimension that makes results non-interchangeable, such as tenant, resource id, representation version or relevant query parameters. Do not include arbitrary unbounded variation without a memory policy, and do not assume a difficult-to-guess key replaces authorization.
Walk cache-aside through hit, miss and failure
In cache-aside, the application checks the cache. On a hit, it returns the eligible cached value. On a miss, it asks the authoritative store, then stores an eligible result for later reuse. The application owns the orchestration.
For a7, a hit avoids a database lookup. A miss is not an error by itself; it is an expected branch. The application reads the mapping and can fill a7 with the destination and expiry policy before returning. Decide whether a cache-fill failure should prevent an otherwise valid read from succeeding.
An authoritative “not found” is different from a database timeout. A short-lived negative cache entry may reduce repeated lookups for confirmed absence. Caching “missing” after a timeout would turn temporary unavailability into a false data result.
Concurrent misses can all load the same key. Cache-aside by itself does not combine them. That creates the stampede problem explored later. Start with the basic read path, then add coordination only where the workload requires it.
Distinguish read-through from application-managed loading
In read-through, a cache layer or library invokes a loader when a value is absent. The caller asks that layer for the value rather than writing the miss orchestration at every call site. The authority and freshness questions still exist.
Centralized loading can make policy consistent, but it can also hide expensive remote work behind an innocent-looking get. Document whether the call can block, which failures it returns and whether concurrent misses are coalesced.
Read-through does not mean every key is always warm or that the loader can safely fetch unlimited values at once. It needs capacity limits, timeouts and a policy for absent or failed loads just as cache-aside does.
Choose based on ownership of the loading code and the operations supported by the implementation. Avoid treating the terms as performance guarantees. Two systems using the same pattern name can behave very differently during an origin outage.
Compare write-through, write-back and write-around
Write-through routes a write through a layer that updates the authoritative store and cache according to its contract before reporting the chosen completion outcome. It can make newly written data available in cache, but the two systems still have failure-ordering questions unless their implementation supplies a stronger atomic boundary.
Write-back, also called write-behind, acknowledges according to the cache or buffering layer’s contract and propagates to the durable authority later. It can absorb or combine writes, but the buffer now holds important accepted work. Persistence, replication, ordering, replay and recovery become correctness requirements.
Write-around writes to the authority without populating the cache with every write. A later read can load the value. This can avoid polluting a read cache with data that will not be read soon, but existing cached copies still need an update or invalidation policy.
For a first mutable short-link design, database-first writes with an explicit cache policy are easier to reason about than introducing a write-back authority. The choice is not universal; the lesson is to follow what a success acknowledgment promises at every step.
Define freshness before optimizing writes
If a destination is immutable, an eligible cached mapping can be reused under a relatively simple expiry policy. If owners can edit or revoke destinations, a reader may receive an older value unless the system coordinates or bypasses copies.
A TTL controls the lifetime of an entry from its insertion or refresh. It does not automatically measure time since the latest database update. A delayed reader can fill an old value after an update, and multiple cache layers can extend the observed path in different ways.
State the required freshness per operation. Public redirects may permit a documented stale window, while an owner’s immediate verification after an edit may use an authoritative path. Security-sensitive revocation may require stronger guarantees than ordinary content freshness.
This choice belongs in the API and product contract. A cache can be technically healthy and still return a value the user is no longer allowed to act on. Faster incorrect results are not a performance improvement.
Evaluate total cost, not hit rate alone
A hit has a cost: key computation, serialization, lookup latency and network transfer for a shared cache. A miss has those costs plus origin work and possibly a fill. If the origin lookup is already cheap and reuse is low, adding a cache can make the path more complex without meaningful benefit.
Hit ratio also hides request value. A cache might serve many tiny cheap hits while the expensive queries all miss. Measure saved origin work, latency distribution, transferred bytes, memory and recovery load.
Local plus shared caching can reduce shared-store traffic, but it introduces another invalidation layer. If A’s local value expires later than the shared entry, deleting the shared key alone will not make A fresh. Model each copy’s lifetime and ownership.
Test empty, partially warm and failed-cache states. A design that works only at its best observed hit ratio has outsourced reliability to a fragile assumption. The recovery path is part of the cache architecture from the beginning.
Guided tutorial
Trace the four outcomes
For a7, write cache hit, cache miss with database value, cache miss with confirmed absence, and cache miss with database timeout. The first returns a copy; the second may fill and return; the third may use a deliberate negative-cache policy; the fourth must remain an unavailable outcome.
Design a safe key
Assume mappings are scoped by tenant. Use the complete tenant and code identity plus any representation version needed by the application. Explain why code alone could return another tenant’s data. Reapply authorization where the operation requires it.
Compare write acknowledgments
Draw database-first and write-back timelines. Mark the exact point the caller receives success and the failures that can occur afterward. For write-back, identify the durable buffer and replay mechanism needed to avoid losing acknowledged work.
Test the cold path
Set the cache to empty in a practice trace and send several simultaneous requests for a7. Count the origin loads under basic cache-aside. Keep that count for the recovery lesson, where same-key coalescing will change it.
Cache-aside pseudocode
value = cache.get(scoped_key)
if value is present:
return value
result = authoritative_store.lookup(code)
if result is a cacheable authoritative result:
cache.set(scoped_key, result, ttl)
return resultCheck your result
A hit performs no database lookup. A miss consults the authority and fills only an eligible result. An unavailable database must not be cached as an authoritative missing code.
04 Cheat sheet
Review the decisions
Use this table to explain the mechanism and its limit without memorizing a product name.
| Choice or concept | Remember | Check |
|---|---|---|
| Cache-aside | Application loads misses | Concurrent fill and invalidation races |
| Write-through | Write path maintains cache and store | Cross-system partial failure still needs a contract |
| Write-back | Persistence is deferred | Pending changes can be lost without durable recovery |
| Write-around | Write directly to backing store | Existing cached copies still need a policy |
05 Where & why
Check the primary references
Use official references for protocol and implementation details. The questions here are teaching prompts.
06 Interview questions
Explain the reasoning out loud
Answer before opening the explanation. The questions progress from vocabulary to decisions and failure behavior.
What does Source of truth mean?
What does Cache-aside mean?
What does Write-back mean?
Why not cache an origin timeout as not found?
How does local cache differ from distributed cache?
Who loads a cache-aside miss?
Is write-through automatically atomic?
When is write-back risky?
07 Practice problems
Practice a new case
Solve the new cases before revealing hints. Complete worked solutions follow the set.
Place the cache
EasyShow the hint
Name the authority
EasyShow the hint
Build a key
MediumShow the hint
Partial write
MediumShow the hint
Negative result
MediumShow the hint
Strategy review
HardShow the hint
Worked solutions
1. Place the cache
A CDN with a correct public/versioned cache policy can avoid origin downloads; browser caching can remove later network requests too.
2. Name the authority
The durable order store is authoritative under this design. The cache is a representation with an explicit freshness rule.
3. Build a key
Include tenant id, product id, locale and any version needed by the invalidation policy. Authorization and cache eligibility remain separate checks.
4. Partial write
Specify acknowledgment, retry identity and invalidation/recovery behavior. Do not claim atomic success across the two independent operations without coordination.
5. Negative result
Reads can keep returning missing until invalidated or expired. Choose short negative lifetimes and creation-path invalidation where appropriate.
6. Strategy review
Cache-aside can suit replaceable summaries with bounded staleness. An acknowledged financial state needs explicit durable authority and recovery; an evictable pending copy without those guarantees is not a sufficient write contract.