Home / Software y Cloud / This is how the cache works: the art of not computing twice

This is how the cache works: the art of not computing twice

Ilustración del concepto de caché en informática

Every time you open a page, your browser sends an HTTP request (the protocol used by web clients and servers to talk to each other) to a machine that may be thousands of kilometers away. If that whole conversation had to start from scratch on every click — database queries, rendered templates, megabytes crossing half the planet — the internet would grind to a halt within minutes. That it does not is thanks to a discreet, ubiquitous mechanism: the cache, which stores the result of expensive work so it never has to be redone.

A cache is a small, fast store that keeps copies of answers that have already been computed. The word comes from French cacher, “to hide”, and the idea is as simple as it is profitable: reading a value from a cache takes microseconds; producing it again can take tens or hundreds of milliseconds. Multiplied by millions of users, that difference is what separates a fast website from one nobody can stand.

The invisible contract: HTTP headers

On the web, caching is not a whim of the server: it is a contract negotiated with the browser through HTTP headers, the metadata that travels at the start of every response. The main one is Cache-Control, which says how long a resource may be kept: max-age=3600 makes it valid for one hour, and no-store forbids storing it (it is used, for example, by responses containing banking data). private limits the copy to the user’s browser; public allows any intermediary to reuse it.

But a URL can return different content over time, and that is where validators come in: ETag, an identifier of the exact version of a resource (a kind of fingerprint), and Last-Modified, the date of the last change. When the browser’s copy grows old, it does not download the whole page again: it sends If-None-Match with the ETag it holds, and if it is still the current one, the server replies with a 304 Not Modified — a practically empty response that means “still the same, keep what you have”. The round trip happens, but the work is not paid for.

The CDN: a shared cache in the middle of the world

The browser is not the only one that caches. A CDN (Content Delivery Network, a network of servers placed between the origin and the users) keeps copies of pages and static files on nodes distributed across the planet, so a user in Galicia receives data from a nearby server instead of from the origin, which may be thousands of kilometers away. It is a shared cache: it serves many users at once, and that raises a problem the private cache does not have: identifying every response.

A cache is indexed by keys, and in HTTP the key is not just the URL. If the same resource can be served compressed with gzip or Brotli, or in two languages, the intermediary must tell the variants apart; otherwise it could serve you the English version of a page requested in Spanish. The Vary header tells the cache which parts of the request are part of the key (Vary: Accept-Encoding is the most common). Omitting Vary is a classic generator of subtle bugs that only show up under real traffic.

CDNs also live with a specific fear: the cache stampede. When a very popular resource expires, hundreds of thousands of requests arrive at an origin that no longer has a copy at the same instant, and all of them compete to regenerate the same data at once. The classic solutions are stale-while-revalidate (serving the old copy while the new one is regenerated) and lock-based throttling: only one request regenerates the resource and the rest wait for its result.

On the server: Redis and the LRU policy

The cache also lives inside the server itself. Instead of recomputing every page by querying the database, applications store intermediate results and frequent queries in in-memory key-value stores such as Redis or Memcached, which keep data in RAM. RAM is expensive and limited, so something has to be evicted when it fills up; the most widespread policy is LRU (Least Recently Used): the entry that has gone the longest without being read is discarded. It is a statistical bet: what has not been touched for a long time will probably not be touched soon.

Let us put it plainly: a cache does not speed up work, it eliminates it. A result served from Redis was not computed at that moment: it was computed once and is being reused. That is why the metric that matters is the hit ratio, the percentage of requests resolved without regenerating the response. Going from 90% to 99% may look like a small jump; under load, it is the difference between a CPU at 20% and one at 80%.

The hardest problem in computer science

There is a phrase attributed to engineer Phil Karlton: “there are only two hard things in computer science: cache invalidation and naming things”. Invalidating a cache means knowing for certain when a copy is no longer valid, and you almost never know. A max-age is a bet in the dark: set it too long and users see stale data; set it too short and you kill the cache, forcing the origin to take all the traffic. Intermediary systems resort to explicit purges (deleting the copy when something changes) and event-based invalidation, but purging down to the last CDN node is slow and not always reliable: that is why companies with critical data — a payment gateway, for instance — prefer no-store and pay the cost of always computing, rather than risk serving an old transaction.

The difficulty adds an irony: the cache wins precisely because content changes little, and fails exactly when it is needed most, when something has just changed and has to be propagated everywhere. The balance between freshness and speed is the real art of the system, and every team solves it with different rules.

The same move at every scale

The most elegant part is that caches are not a web trick: it is the same pattern at every level of computing. Inside your processor, the L1, L2 and L3 levels are SRAM caches, progressively larger and slower, that keep the CPU from having to fetch data from RAM; the operating system keeps a page cache of disk blocks that have already been read; your DNS server stores domain resolutions for their TTL (Time To Live, the lifetime set by the domain owner); even databases keep their most-queried indexes in memory. In every case the strategy is identical: keep hot data close, and decide carefully when to look back at the source.

At its core, the cache is engineering’s answer to an uncomfortable truth: computing is expensive. Whoever designs a modern system spends as much time deciding what to cache and how to invalidate it as writing the logic that solves the problem; a well-placed cache turns milliseconds into microseconds and makes it possible for a click in A Coruña to be answered from a node tens of kilometers away. Next time a page opens instantly, you know who did the work while you were not looking.