12. Caching: The Basics
12.4 On a miss, who fetches the data?
Reading and writing
In the kitchen: When the fridge is empty, someone has to go to the shop. Either you go, then put a carton in the fridge yourself; or you have a smart fridge that orders milk itself when you open an empty door.
In the system: These are the two read strategies.
Figure: same result; the difference is whose code knows about the database.
12.4.1 Cache-aside (lazy loading)
In the kitchen: You check the fridge, you go to the shop on a miss, and you stock the fridge on the way back.
In the system: The application owns the logic. It checks the cache; on a miss, it reads the database, writes a copy into the cache with a TTL, and returns it. This is exactly the flow in 12.1, and it's the most common pattern.
- Only data that's actually requested gets cached. No wasted memory.
- If the cache is down, the app can still read the database (slower, but working).
- The cost: the first request for each key is always a miss, and every place in your code that reads must remember to do this.
12.4.2 Read-through
In the kitchen: The smart fridge orders milk itself. You only ever talk to the fridge.
In the system: The app asks only the cache. On a miss, the cache itself (or a cache library in front of it) loads the value from the database, stores it and returns it. The loading code is written once, inside the cache layer.
- Cleaner app code: one place knows how to load each kind of data.
- The cost: you need a cache layer or library that supports it, and that layer now depends on the database.
Many teams use a small read-through wrapper in their own code ("give me product X; load it if missing") on top of a plain Redis, which gives the cleanliness of read-through with the control of cache-aside.
Memory code: "Cache-aside: you go to the shop. Read-through: the fridge goes for you."