Building block

Caching

Stores the results of expensive operations in fast storage so they are not computed again. The cheapest way to speed up reads, as long as you decide correctly when the cache goes stale.

Cache-aside: cache first, database on a miss, invalidation on writeGET / SET+TTLmissUPDATEDEL keyClientApplicationRedisCourse editorPostgreSQL
Cache-aside: cache first, database on a miss, invalidation on write

Why cache: the numbers

Reading from process memory takes nanoseconds, a Redis call in the same data center about 0.2 to 0.5 ms, a simple indexed PostgreSQL query 1 to 5 ms, and a complex dashboard aggregate easily 100 ms or more. A cache turns the latter into the former.

The key metric is hit ratio. If 95% of course page requests in ShortLesson are served from cache, the database sees 20 times less load. Caches live at several levels: the browser, the CDN, the application cache (Redis, Memcached), the database's own cache.

Patterns: cache-aside and write-through

Cache-aside (lazy loading) is the most common: the app first reads GET course:42 from Redis. On a miss it reads from the database and stores the result in the cache with a TTL. Only data that is actually requested gets cached.

Write-through: on every write the app updates both the database and the cache. The cache is always fresh, but each write is slower, and the cache fills with data nobody may read. Write-behind writes to the cache first and to the database asynchronously: fast, but you risk losing data if the cache fails.

TTL and invalidation

TTL sets how long a key lives: 60 seconds for a list of popular courses, 10 minutes for an author profile, a day for reference data. A short TTL means fresher data and a lower hit ratio, a long one the opposite.

Invalidation on write: you update a course in the database, then immediately DEL course:42. Deleting beats overwriting because it leaves fewer races between concurrent writes. For complex dependencies, tags or versions in the key (course:42:v7) help.

Cache stampede

When a popular key expires, hundreds of requests miss at once and all go to the database for the same thing. A database that lived quietly thanks to the cache suddenly gets a spike and falls over.

Defenses: locking (only one request rebuilds the key, the rest wait or get the old value), random TTL spread (jitter, for example 300 ± 30 s), early background refresh before the TTL ends, and stale-while-revalidate. Facebook described «leases» in Memcache for exactly this problem.

Pros

  • Read latency drops from milliseconds to fractions of a millisecond.
  • The database gets many times less load.
  • Cheap: one Redis often replaces several database replicas.
  • Smooths spikes on popular data.

Cons

  • Stale data: invalidation is one of the hardest problems.
  • Cache stampede when hot keys expire.
  • Another system to monitor and scale.
  • A cold start after a cache restart hits the database.

When to choose it

  • Reads far outnumber writes.
  • The same data is requested many times (catalog, profiles, settings).
  • Computation is expensive and slight staleness is acceptable.
  • You need to take load off the database without sharding.

Where it is used

  • Facebook: «Scaling Memcache at Facebook» (NSDI 2013), including leases against stampedes.

Tools

Sources

Logos belong to their owners and are used for identification only. Icons: Simple Icons (CC0), Devicon (MIT).