Redis vs Memcached
Both are in-memory caches, but they made different architectural bets. Compare them side by side and use the decision helper to pick one for your workload.
🎯 What you'll learn
- What each one optimizes for
- Feature, threading, persistence and replication differences
- Choosing by workload
- Why the architectures diverged
1The Question This Topic Actually Answers
Both tools solve "keep hot data in RAM so I don't hit the database every request." The interesting question isn't "which is faster" (for a plain get/set of a small string, both are sub-millisecond and the difference is noise) — it's which mechanical design decisions each one made, and which real workloads those decisions favor. 01-redis/cache_redis_theory.md and 02-memcached/cache_memcached_theory.md each cover one side in depth; this file is the head-to-head.
2Side-by-Side
| Redis | Memcached | |
|---|---|---|
| Value types | strings, hashes, lists, sets, sorted sets, streams | opaque byte strings only |
| Execution model | single-threaded event loop | fixed multi-threaded pool, shared locked hash table |
| Max value size | 512MB (string) | 1MB default |
| Persistence | RDB snapshots and/or AOF log | none — restart empties everything |
| Replication / clustering | built-in (Redis Sentinel, Redis Cluster) | none server-side; client-side sharding only |
| Concurrency-safe compound ops | MULTI/EXEC, WATCH, and atomic type-specific commands (HINCRBY, ZADD, ...) | cas/gets, incr/decr — narrower primitive set |
| Pub/Sub or messaging | Pub/Sub (fire-and-forget) + Streams (durable, replayable) | none |
| Eviction policy | selectable (allkeys-lru, allkeys-lfu, volatile-ttl, noeviction, ...) | fixed strict LRU per slab class, not configurable |
| Memory allocation | generic allocator (jemalloc by default) | slab allocation with fixed chunk-size classes |
| Multi-core scaling (single instance) | needs Redis Cluster / multiple instances to use more cores | one process uses multiple cores natively via its thread pool |
| Typical role | cache and/or primary data store / broker / queue backend | cache only |
3Choosing Based on the Actual Workload
Favor Memcached when:
- The workload is purely simple key -> flat-blob caching (rendered HTML fragments, serialized API responses) with no need for server-side structure operations.
- You want to maximize raw throughput per box for that narrow workload by using every CPU core in one process.
- You explicitly do NOT want persistence — an empty-on-restart cache is a correctness feature here, not a gap, because you never want stale-but-durable data surviving a deploy.
Favor Redis when:
- You need atomic operations on structured data server-side (increment one hash field, push onto a capped list, maintain a leaderboard) without round-tripping the whole blob to the client.
- You want the cache to survive a restart without a full cold-cache thundering herd (see
05-cache_invalidation/cache_cache_invalidation_theory.md), via RDB/AOF. - You need pub/sub, streams, rate-limiting primitives, distributed locks (
SETNX/SET ... NX), or geo commands — none of which have a Memcached equivalent. - You want built-in replication/clustering rather than building your own client-side sharding layer.
4What They Genuinely Share
Both are volatile-by-assumption caches sitting in front of a slower source of truth; both expect the application to handle cache misses by querying that source of truth (this is the cache-aside pattern covered fully in 06-cache_aside_write_through_write_behind/); both rely on TTL for automatic staleness bounding (07-ttl/); and both, at multi-node scale, depend on consistent hashing to route a given key to a specific node predictably (08-distributed_caching/).
Under the HoodWhy the Architectures Diverged, Mechanically▾
This is the crux, not a footnote. Memcached's single-type, no-persistence, no-replication design is not an earlier, less mature version of what Redis became — it is a deliberately narrower system, and the narrowness is what buys its concurrency model.
Because a Memcached value is an opaque blob with exactly one operation shape ("replace these bytes" / "read these bytes," plus incr/decr for the special case of a numeric string), multiple threads can service unrelated keys with only fine-grained per-bucket locking — there is no cross-key invariant a lock has to protect beyond "don't corrupt this one hash bucket while it's being mutated." A get key1 and a set key2 can execute genuinely concurrently on different cores with only brief mutual exclusion, if any, on the shared structures they each touch.
Redis's data model breaks that independence. A single logical operation like ZADD has to correctly update a sorted set's dual backing structure (skip list and hash table, kept consistent with each other) as one atomic step, and richer future commands can combine multiple keys (SINTERSTORE, MULTI/EXEC blocks touching several keys) with a correctness requirement that nothing else runs in between. Redis's authors chose to buy that correctness for free — no lock design, no risk of forgetting a lock, no lock contention overhead — by making the entire command execution path single-threaded, accepting the throughput ceiling of one core for command execution in exchange. Memcached's authors chose to buy raw multi-core throughput by keeping the data model simple enough that locking could stay cheap and local.
Neither choice is a mistake the other project corrected; they are two different answers to the same trade-off (concurrency-model complexity vs. data-model richness), each internally consistent with what the tool is for.
⚠️ Common Pitfalls
- Assuming one is a strict upgrade of the other — picking Redis "because it can do more" for a workload that's genuinely just flat-blob caching adds operational complexity (persistence config, richer failure modes) for no benefit.
- Running Memcached but architecting as if it persists — after any restart/crash/OOM-kill, the cache is empty; code paths must tolerate a 100% cache-miss cold start.
- Running single-instance Redis and expecting Memcached-like multi-core throughput — a single Redis process caps command execution at one core; horizontal scaling requires Redis Cluster or multiple instances, not just "more Redis on the same box."
- Comparing raw benchmark numbers out of context — for trivial get/set of small values, both are sub-millisecond; meaningful differences only show up under specific access patterns (many small independent keys favoring Memcached's parallelism, or compound structured operations favoring Redis's atomics).
- Forgetting Memcached has no selectable eviction policy — if you need
volatile-ttlorallkeys-lfusemantics, that requirement alone rules out Memcached.
📋 Quick Reference
Redis Memcached
Data types strings, hash, list, set, strings only (opaque bytes)
zset, stream
Concurrency single-threaded event loop thread pool + fine-grained locks
Persistence RDB and/or AOF none
Replication built-in (Sentinel/Cluster) none (client-side sharding only)
Eviction selectable policy fixed strict LRU per slab class
Best for structured ops, durability, pure flat-blob caching,
pub/sub, rate limiting max per-box throughput🧠 Key takeaways
- Redis: data structures, scripting, replication/failover, persistence; single-threaded command execution.
- Memcached: plain blobs, multi-threaded, no persistence or replication, client-side distribution.
- Choose by workload needs, not popularity; Redis is the common default today.
- Both are caches first: design for misses and node loss.
🎤 Interview Q&A
Q1Compare Redis and Memcached.core▾
Redis: rich data structures, persistence, replication, clustering, Lua scripting, pub/sub, streams; mostly single-threaded command execution. Memcached: simple strings, multi-threaded, no persistence or replication, client-side sharding. Redis is more versatile; Memcached is simpler for pure caching.
- Default choice today? Redis, unless you need Memcached's simplicity and multi-threading.
Q2Which scales better on a single node?core▾
Memcached uses all CPU cores for request handling. Redis executes commands on one thread (with I/O threads), so one instance may be CPU-bound sooner; you scale Redis by running more shards.
- Is single-threaded Redis slow? No; it handles ~100k+ ops/s per instance.
Q3When does Redis's persistence matter for a cache?senior▾
When a cold cache after restart would overload the database (warm restarts from RDB/AOF), or when Redis stores data that's more than a cache: sessions, rate limits, queues, leaderboards.
- Should you rely on Redis as the system of record? Only with persistence and replication tuned for it, and an understanding of async replication loss.
Q4How do eviction policies differ?core▾
Memcached uses LRU per slab class. Redis offers configurable policies: allkeys-lru, allkeys-lfu, volatile-lru (only keys with TTL), noeviction (errors when full), and random/TTL variants.
- Best policy for a cache?
allkeys-lruorallkeys-lfu.
Q5How do they handle high availability?core▾
Redis has built-in replication, Sentinel failover and Cluster. Memcached has none; clients treat a lost server as cache misses, possibly with replication via proxies like mcrouter.
- Is losing a cache node acceptable? If the database can absorb the misses; otherwise protect it with HA and request coalescing.
🛠️ Practice exercises
Each exercise is a file in this topic folder. Code exercises are self-checking: run them and make the checks pass.
✅ Check yourself
Answer the questions — feedback is instant.