A web backend can cache data in five layers. From the user inward:
- The client: the browser HTTP cache and the app's own memory.
- The CDN or edge: servers near the user that keep copies of responses.
- A reverse proxy cache, such as Nginx, in front of your app servers.
- The application: in-process memory, or a distributed cache like Redis.
- The database itself: its buffer pool keeps hot (often-used) pages in memory.
The closer a cache is to the user, the faster a hit is. It also saves more load on the layers behind it. But it is harder to invalidate (remove or refresh stale data), and you have less control. For example, you cannot purge a user's browser cache. So you rely on TTLs (time to live: how long an entry stays valid) and versioned URLs like app.v2.js.
In-process caches are the fastest inside the backend. But each app instance holds its own copy, so two instances can return different values. A shared Redis cache gives the same value to every instance. The cost is a network hop on each read.
In short: cache only data that can be a little stale, and decide for each layer how stale is acceptable.
- You can cache in the client, the CDN, a reverse proxy, the app (in-process or distributed) and the database.
- A cache closer to the user is faster and saves more load behind it.
- A cache closer to the user is harder to invalidate and gives you less control.
- In-process caches can hold different values on different instances.
- Decide for each layer how much staleness is acceptable.