Notes
The problem
Here's the problem. A user in Chennai loads a page served from Virginia, fourteen thousand kilometres away. Even at the speed of light in fibre, each round trip takes a few hundred milliseconds, and a page has dozens of files. Meanwhile every user in the world hammers the same origin servers.
- Chennai ↔ Virginia ≈ 14,000 km
- light in fibre: ~200 km per ms
- → ~140 ms one way, best case
- a page with 60 files,
- TLS handshakes, retries…
- and every user hits
- the same origin servers
Edge servers
A content delivery network runs hundreds of edge servers around the world. DNS sends each user to the nearest one. If the edge has a copy of the file, it answers in a few milliseconds, and the request never reaches your origin.
- hundreds of edge locations
- (points of presence) worldwide
- DNS sends each user to
- the nearest edge
- edge has a copy → serve it
- Cloudflare, CloudFront, Akamai,
- Fastly
Hit or miss
The first request for a file at an edge is a miss: the edge fetches it from your origin, usually backed by object storage, keeps a copy and returns it. Everyone nearby after that gets a hit. With a ninety-five percent hit ratio, your origin sees only one request in twenty. That's a pull CDN; a push CDN has you upload files ahead of time.
- first request at an edge: MISS
- edge fetches from origin,
- stores it, returns it
- next requests: HIT
- hit ratio 95% →
- origin sees 1 in 20 requests
- push CDN: you upload files
- to the CDN ahead of time
Headers
Your origin controls caching with the Cache-Control header. Public with a max age of a year means cache it for a year. Private, no store means never cache it, for anything user-specific. And stale-while-revalidate lets the edge serve a slightly old copy while it fetches a fresh one in the background.
Cache-Control: public, max-age=31536000, immutable → cache for a year Cache-Control: private, no-store → never cache (account pages) Cache-Control: max-age=60, stale-while-revalidate=300 → 1 min fresh, then refresh in the background
Versioning
The cleanest trick is to put a hash of the content in the file name: app dot three f nine a, dot js. A new deploy produces a new name, so you can cache scripts, styles and images forever, cache the HTML only briefly, and never worry about users getting a stale script.
app.js → which version? app.3f9a1c.js → content hash new deploy = new file name old copies just expire HTML points to the new name cache JS/CSS/images forever, cache HTML briefly
Invalidation
If you must change a file without renaming it, CDNs let you purge it, by path, prefix or tag, and the purge spreads to every edge within seconds to minutes. It works, but treat it as the emergency tool. Versioned file names avoid the problem entirely.
- changed a file with the same
- name? purge it:
- purge /images/logo.png
- purge by tag or prefix
- takes seconds to minutes
- across all edges
- prefer versioned names;
- purge is the emergency tool
More
Modern CDNs do more than store files. They terminate TLS close to the user, absorb denial-of-service attacks, compress responses, resize images on the fly, stream video in small chunks, and can even run code at the edge. Just never cache personal data as public.
- terminate TLS near the user
- absorb DDoS attacks
- compress (gzip, brotli)
- resize and convert images
- stream video in chunks (HLS)
- cache some API responses
- run code at the edge
- personal data: never public-cache
Say it like this
In an interview: store images and video in object storage, serve them through a CDN with content-hashed names and long cache times, keep HTML and API responses short-lived or uncached, and use signed URLs for private media. Mention that origin load drops to one minus the hit ratio.
- "Users are global, media is big"
- images/video in object storage
- served through a CDN
- content-hashed file names,
- long max-age
- HTML and APIs: short or no cache
- signed URLs for private media
- origin load ≈ (1 − hit ratio)