Caching Strategies
You'll learn to
- -Describe how cache-aside reads and writes work, and why it is the usual default
- -Contrast write-through and write-behind in speed, freshness and risk
- -Spot the stale-data race in cache-aside and say what bounds it
- -Choose a pattern for a kind of data and name its failure mode
Knowing that a cache pays off is the easy part. The real design work is deciding how data gets into the cache and how it stays correct when the data changes. There are a few common patterns, and the one you pick decides what happens on every read and every write, and what you could lose if something crashes.
An Analogy: A Notebook on Your Desk
Imagine you answer questions for a company, and you keep a notebook on your desk with answers you have looked up before. The filing room down the hall holds the real records and is the source of truth. Each pattern is a different habit for using the notebook.
- -Cache-aside: you check the notebook. If the answer is missing you walk to the filing room, then copy the answer into the notebook before replying. You manage the notebook yourself.
- -Read-through: the same, except a clerk stands between you and both places. You only ever ask the clerk, who checks the notebook and fetches from the filing room for you.
- -Write-through: when an answer changes you update the filing room and the notebook together, and only then say done.
- -Write-behind: you update the notebook straight away and promise to update the filing room later, in a batch. It is fast, but if the notebook is lost before the batch is carried over, the change is lost.
- -Write-around: you update the filing room only and leave the notebook alone, so it is not filled with answers nobody asks for again.
Cache-Aside: The Default
Cache-aside, also called lazy loading, is the most common pattern because it is simple and fails gently. On a read, the application looks in the cache. On a hit it returns the value. On a miss it reads the database, stores the value in the cache with a time-to-live, and returns it. On a write, it updates the database and then removes the cached copy, so the next read refills it with fresh data. If the cache goes down, the application still works, only more slowly, because the database remains the source of truth.
The diagram shows the read path: the application asks the cache first and goes to the database only on a miss.
Cache-aside: the application checks the cache first, and only falls through to the database on a miss.
There is one subtle trap. Suppose a reader misses and fetches the old value from the database. Before it can store that value in the cache, a writer updates the database and deletes the cached key. The reader then stores the old value it fetched, and the cache now holds stale data until its time-to-live runs out. This is rare, which is part of why cache-aside is so widely used, but it is the reason every cached value should have a time-to-live as a safety net.
Write-Through and Write-Behind
In write-through, every write goes to the cache and the database together before the caller is told it succeeded. The cache is never stale, but each write pays for both, so writes are as slow as the database. In write-behind (also called write-back), the write goes to the cache only, and the cache saves it to the database a moment later, often combining many writes into one. Writes feel very fast, but for a short window the only copy of the data is in the cache, and a crash inside that window loses it.
Write-behind: the write is acknowledged once it reaches the cache, and the database is updated later
Choosing a Pattern
- -Read-heavy data that can be a little stale: cache-aside with a time-to-live (product pages, profiles).
- -The cache must never be stale, and you can afford slower writes: write-through (a user's settings, read straight after being saved).
- -Write-heavy data where a small loss window is acceptable: write-behind (counters such as view counts, activity metrics).
- -Data written once and rarely read: write-around, so it does not push hot items out of the cache.
- -Money, orders, or anything that must never be lost: never write-behind.
A strong interview answer names the pattern and its failure mode in one breath, for example: I would use cache-aside with a 5-minute time-to-live. If the cache dies we fall back to the database, and a stale entry lives for at most five minutes.
The Wiki card below compares the patterns side by side, with when to use each:
Store computed or fetched results in a fast store (usually Redis) to avoid repeating expensive work. The patterns for populating and invalidating caches are where the complexity lives.
You run a restaurant. Instead of cooking every dish from scratch, you pre-cook the most popular dishes at 11am before lunch rush (Cache-Aside pre-warm). When someone orders, you check your ready-made shelf first. If it's there, serve immediately. If not, cook it - and put a fresh copy on the shelf.
Cache-Aside (Lazy Loading): The most common pattern. Application checks cache first. On miss, app fetches from DB, stores in cache, returns result. The cache is only populated on misses - "lazy" means you only cache what's actually requested. Simple to implement. Risk: cache stampede on cold starts.
Write-Through: Every write to the database simultaneously writes to the cache. Cache is always warm and consistent with the DB. But every write now takes twice as long (must update both DB and cache). Also wastes cache space for data that may never be read.
Write-Behind (Write-Back): Writes go to the cache first and return immediately. A background worker asynchronously flushes to the database. Ultra-low write latency. Risk: data loss if the cache crashes before flush. Used for analytics counters, batch operations.
Read-Through: The cache sits transparently in front of the database. Application reads from cache; if miss, the cache itself fetches from DB and stores it. Simplifies application code. The caching layer (not the app) manages misses.
Cache Invalidation is infamously hard. Two strategies: TTL (expire after N seconds - simple but potentially stale) and Event-Driven invalidation (publish a cache-busting event when the DB record changes - complex but accurate). Phil Karlton's famous quote: "There are only two hard things in Computer Science: cache invalidation and naming things."
- -Cache Hit Ratio = hits / (hits + misses). Target > 90% for meaningful impact.
- -TTL too short = too many DB hits. TTL too long = serving stale data.
- -Never cache data that changes every request or is user-specific-sensitive (PII).
- -Cache eviction policies: LRU (Least Recently Used), LFU (Least Frequently Used), TTL.
- -Warm the cache on startup for critical paths to avoid cold-start stampedes.
In one line: the patterns differ in who fills the cache and when the database is told. Cache-aside is the default, write-through buys freshness with slower writes, and write-behind buys fast writes with a window in which data can be lost.
Interview Signal is part of Pro
See a real weak answer next to a real strong one for this exact topic.
Quiz is part of Pro
Test what you just read with a short quiz, and bank the XP.
Discussion0
Join the Discussion
Sign in to leave comments, reply to others, or like insights.
No comments yet. Be the first to start the thread!