Skip to content

Back to blog

Cache

Cache invalidation without the headache

· 7 min

Cache invalidation is famous for being "one of the two hard problems" in computing, but the most common way it goes wrong in practice isn't picking the wrong algorithm, it's never explicitly deciding who owns invalidating what.

Illustration of a circular refresh arrow

TTL alone is a bet, not a strategy

A short TTL keeps data fresh at the cost of hitting the database more often; a long TTL saves load at the cost of serving stale data for longer. Relying on TTL alone works fine when that window of inconsistency is genuinely acceptable for the use case, and becomes a silent problem when it isn't, because the system never signals that it's serving something old.

Event-driven invalidation: whoever writes, tells

With event-driven invalidation, the code path that mutates the data is itself responsible for deleting or updating the corresponding cache entry, giving near-immediate consistency. The cost is coupling: every write path needs to know which cache keys depend on that data, and forgetting one is the most common way this pattern fails silently.

Cache stampede: when everyone hits the database at once

When a heavily-accessed key expires, multiple concurrent requests can all see the miss at the same time and all fire at the database together to repopulate the cache, a small expiration turns into a real load spike. The usual mitigations are request coalescing (only one request actually recomputes, the rest wait on its result) and probabilistic early expiration, refreshing the entry slightly before its real deadline to spread the load over time.

Cache-aside vs write-through

In cache-aside, the application checks the cache, falls back to the database on a miss, and populates the cache afterward, simple, but with a window where cache and database can diverge. In write-through, every write goes through the cache layer itself, which keeps the two in sync at all times, more consistent, at the cost of more complexity on the write path.

The question that avoids the headache

Before picking an invalidation strategy, it's worth explicitly deciding, for each piece of cached data, who is responsible for invalidating it and under what event. Most cache bugs don't come from the wrong algorithm, they come from that ownership never having been decided at all.