Steven's Knowledge

Cache

In-memory caching with Redis and Memcached - patterns, deployment, and how to avoid the classic cache pitfalls

Cache

A cache is a fast, usually in-memory store that holds copies of expensive-to-compute or expensive-to-fetch data so the next request doesn't pay the full cost. Cache the result; serve the next 1,000 reads from RAM. Done right, it's the cheapest way to scale a read-heavy system.

Why Cache

Without cacheWith cache
Every request hits the databaseMost reads served from memory in < 1 ms
Database CPU scales with trafficDatabase CPU scales with write traffic
Recomputing the same expensive queryCompute once, reuse for the TTL
Tight coupling between read latency and DBDecouple: cache is fast even when DB is slow
Hard to handle traffic spikesCache absorbs bursts

The Players

SystemNotes
RedisThe default. In-memory data structures (strings, hashes, sorted sets, streams), persistence, pub/sub, clustering.
MemcachedOlder, simpler, multi-threaded, only key-value strings. Very fast at what it does.
DragonflyDBDrop-in Redis replacement; multi-threaded, claims higher throughput.
KeyDBMulti-threaded Redis fork.
ValkeyLinux Foundation fork of Redis (after Redis license change in 2024).
Hazelcast / Apache IgniteDistributed in-memory data grids; richer than a cache.
ElastiCache / MemoryStore / Azure CacheCloud-managed Redis/Memcached.

For most use cases: start with Redis (or Valkey, the OSS fork). Memcached is excellent if you only need key-value and want raw throughput.

Redis vs Memcached

AspectRedisMemcached
Data structuresStrings, hashes, lists, sets, sorted sets, streams, HyperLogLog, geo, bitmapsStrings only
PersistenceOptional RDB snapshots + AOFNone
ReplicationBuilt in (primary-replica, cluster mode)Sharding only, no replication
ThreadingSingle-threaded core (multi-threaded I/O since 6.0)Multi-threaded
Eviction policiesMultiple (LRU, LFU, TTL, random, no-eviction)LRU
Pub/SubYesNo
Transactions / scriptingMULTI/EXEC, Lua scriptingNo
Use when...Anything non-trivial; sessions, queues, leaderboardsPure read-through cache with simple values

The trend is clear: Redis is the broader, more flexible default. Memcached is great when its constraints fit your workload.

Learning Path

Where Caches Live

Browser ──► CDN cache ──► API gateway ──► App ──► Local cache ──► Distributed cache (Redis) ──► Database
            (geo)        (response)      (in-memory LRU)         (shared across pods)        (source of truth)

A typical request can hit cache at five layers before reaching the database. Each layer has different TTLs, invalidation rules, and sizing concerns. This page is about the distributed in-memory layer (Redis/Memcached) — for HTTP caching see CDN.

What to Cache (and Not To)

Good cache candidatesBad candidates
Computed query resultsPer-request mutations
Per-user profile / sessionStrongly consistent data (account balances)
Hot read paths (top product list)Anything you can't reconstruct from source
Aggregations (counts, sums)Tiny rows trivially fetched from DB
Third-party API responses (rate-limited)Anything with PII you don't have a retention policy for

A cache is not the source of truth. Anything in cache must be reconstructible from the database. If you'd cry when the cache server dies, you're using it as a primary store — and probably about to have a bad week.

Caches add a consistency problem. Stale data, dual writes, race conditions on invalidation — all the bugs that don't exist without a cache appear with one. Adopt a cache deliberately, not reflexively.

On this page