26. CDNs
26.4 How do cache keys and headers work?
In the warehouse: Every carton has a label saying exactly what it is, so a warehouse doesn't stock "Marie biscuits, 200 g" fifty times under fifty slightly different names. And every carton has a use-by date, so the warehouse knows when to stop selling it.
In the system: Two things decide what a CDN caches: the cache key (which requests count as the same object) and the headers (whether, and for how long, to keep it).
Figure: get the key right so copies are shared; get the headers right so the right things are cached for the right time.
The cache key is usually the host + path + query string, plus any request headers listed in Vary:
- Strip noise.
?utm_source=igand?utm_source=waare the same cover. In the chapter's code, 50 links with different tracking parameters create 50 cache entries (50 misses); normalised, they're 1. - Sort query parameters, so
?q=dune&page=2and?page=2&q=dunematch. - Be careful with
Vary.Vary: Accept-Encodingis fine (a few variants).Vary: CookieorUser-Agentcreates almost one entry per user and destroys your hit ratio.
The headers come from the origin's Cache-Control:
| Directive | Meaning |
|---|---|
public | Any cache (browser, CDN) may store it |
private | Only the user's browser may store it, never a shared cache |
no-store | Nobody stores it |
max-age=N | Fresh for N seconds (browsers and CDNs) |
s-maxage=N | Fresh for N seconds in shared caches only (overrides max-age for the CDN) |
immutable | Will never change at this URL; don't even revalidate |
stale-while-revalidate=N | Serve the old copy for up to N seconds while fetching a new one in the background |
stale-if-error=N | Serve the old copy for up to N seconds if the origin is failing |
Plus validators: ETag and Last-Modified let a cache ask "has it changed?" (If-None-Match) and get a tiny 304 Not Modified instead of the whole file.
Typical choices for the bookstore:
- JS, CSS, covers with versioned file names (
app.3f9a1c.js,cover-42-v3.jpg):public, max-age=31536000, immutable. A change gets a new URL, so nothing ever needs purging. - Book pages (same for everyone, change occasionally):
public, max-age=60, s-maxage=300, stale-if-error=600. Browsers check often, the CDN keeps it 5 minutes, and it survives an origin outage for 10. - Account, cart, checkout:
private, no-store. Never in a shared cache (the Level 4 bug).
Memory code: "One label per product, and a use-by date on every carton."