A pure cache or a data structure server: decide by whether you need more than GET and SET.
How to choose an in-memory store, and how to justify it in an interview. Short version: Memcached is a pure cache; Redis is a data-structure server that also caches. If the answer is not obvious, ask whether you need anything besides GET and SET.
| Dimension | Redis | Memcached |
|---|---|---|
| Data model | Strings, hashes, lists, sets, sorted sets, streams, pub/sub | Strings (bytes) only |
| Threading | Mostly single-threaded event loop (I/O threads in newer versions) | Multi-threaded; scales up on one box |
| Persistence | Optional (RDB snapshots, AOF log) | None; a restart is a cold cache |
| Replication / HA | Built in (replication, Sentinel, Redis Cluster) | None built in; clients shard with consistent hashing |
| Eviction | Configurable policies, TTL per key | LRU with slab allocation; TTL per key |
| Atomic operations | Rich: INCR, compare-ops via Lua scripts, transactions | INCR/DECR, CAS |
| Memory efficiency for plain strings | Good | Slightly better (simpler allocator, less metadata) |
Start at the top. The memory question disqualifies both before the comparison even matters:
flowchart TD
A{"Does the working set<br/>fit in memory?"} -->|no| N["Neither. Fix the data model,<br/>or use a disk store"]
A -->|yes| B{"Do you need anything<br/>besides GET and SET?"}
B -->|no| M["Memcached:<br/>look-aside cache, simplest ops,<br/>highest throughput per node"]
B -->|"data structures"| R1["Redis: sorted sets, INCR<br/>with expiry, lists, streams"]
B -->|"must survive a restart"| R2["Redis with persistence<br/>and replicas"]
B -->|"distributed locks"| R3["Redis: SET NX with expiry"]
- Pure look-aside cache for serialized blobs, biggest possible throughput per node, simplest ops → Memcached. This is the Facebook use case.
- You need the data structures → Redis, and name the mapping: sorted sets for leaderboards, INCR with expiry for rate limiting, lists/streams for lightweight queues, sets for presence.
- Cache that must survive restarts, or cache plus source-of-truth-ish state (sessions you cannot lose) → Redis with persistence and replicas.
- Distributed locks → Redis (SET NX with expiry), with the caveats in distributed locking.
- Both are RAM-priced: if the working set does not fit in memory, neither is the answer; fix the data model or use a disk store.
- Cache invalidation: delete-on-write vs TTL-only, and what staleness window the product tolerates.
- Thundering herd on hot-key expiry: request coalescing, jittered TTLs, or leases (Memcached's lease trick).
- Redis single-threaded caveat: one slow command (KEYS, huge SMEMBERS) stalls everything; big values and scan-style commands are the classic self-inflicted outage.
- Failure semantics: Memcached loss is a performance event (cold cache, database takes the misses); Redis-as-state loss is a correctness event. Decide which one you are running.
Do not say "I would add Redis because it is fast". Say "this is a read-heavy feed; I need a look-aside cache for rendered cards keyed by post id, TTL plus delete-on-write, and nothing fancier, so Memcached (or Redis used as a plain cache) behind consistent hashing. Separately, the leaderboard needs sorted sets, so that specific feature runs on Redis." Choosing per workload, not per brand, is the senior signal.
- Caching pattern and the Memcached at Facebook deep dive
- Full course: Grokking the System Design Interview