Lesson 33 of 129
Redis and Memcached
Redis and Memcached are in-memory key-value servers used mainly as caches. Memcached stores opaque values under string keys. Redis stores typed data structures, can persist data to disk, and provides replication and clustering. Both serve requests from RAM with latencies well under a millisecond on a local network.
Redis data structures
Redis values have a type, and commands operate on the type on the server, so clients do not need to read, modify, and write the whole value.
| Type | Description | Typical use |
|---|---|---|
| String | bytes, up to 512 MB; integer operations such as INCR |
cached objects, counters, locks |
| Hash | field-to-value map under one key | object fields, partial updates |
| List | ordered list, push/pop at both ends | queues, recent items |
| Set | unordered unique members | tags, unique visitors, set operations |
| Sorted set | members ordered by a score, O(log n) insert |
leaderboards, priority queues, rate-limit windows |
| Stream | append-only log with consumer groups | event streams |
| Bitmap, HyperLogLog, Geo | bit operations, approximate cardinality, geospatial queries | flags, unique counts, proximity |
Keys can carry a TTL (EXPIRE, SET ... EX). Expired keys are removed lazily on access and by a periodic sampling process.
Single-threaded command execution
Redis executes commands on one thread. Each command is atomic, because no other command runs concurrently, and no locks are needed inside the data structures. The event loop multiplexes many client connections using I/O readiness notification (epoll and similar). Newer versions can use additional threads for network reading and writing, but command execution stays serial.
Consequences:
- Throughput is bounded by one core for command execution. Scale further with more instances (sharding).
- A slow command blocks all clients.
KEYS *, largeSMEMBERS, and long Lua scripts are hazards; use incremental iteration (SCAN) instead. - Multi-step atomicity is available through
MULTI/EXECand Lua scripts, which run without interleaving.
Persistence
By default memory is volatile. Redis offers two persistence mechanisms, usable together.
| RDB snapshot | AOF (append-only file) | |
|---|---|---|
| What is stored | point-in-time binary dump of the dataset | log of every write command |
| Trigger | periodic rules (every N seconds if M changes), or manual | each write appended; fsync policy configurable |
| Data loss on crash | changes since the last snapshot | depends on fsync: every write, every second, or left to the OS |
| Restart speed | fast (load the dump) | slower (replay the log) |
| File size | compact | larger; periodically rewritten to compact it |
RDB snapshots are produced by a forked child process, so the parent keeps serving requests. The child sees a copy-on-write view of memory: pages the parent modifies during the snapshot are duplicated, so memory use can grow with the write rate while a snapshot or AOF rewrite runs. AOF with fsync every second is a common compromise between durability and speed. Persistence in Redis is asynchronous with respect to clients unless configured to fsync on every write, so Redis is not a replacement for a durable database by default.
Replication and Sentinel
Redis replication is leader-follower (called primary and replica). A replica connects to the primary, receives an initial snapshot, and then a stream of write commands. Replication is asynchronous by default, so a failover can lose the most recent writes. Replicas serve reads, which may be stale.
graph LR
P["Primary"] -->|"async command stream"| R1["Replica 1"]
P -->|"async command stream"| R2["Replica 2"]
S1["Sentinel 1"] -.->|monitor| P
S2["Sentinel 2"] -.->|monitor| P
S3["Sentinel 3"] -.->|monitor| PRedis Sentinel provides high availability for a non-clustered deployment. A group of Sentinel processes monitors the primary and replicas. When a configurable quorum of Sentinels agree the primary is unreachable, it is marked objectively down. The Sentinels then elect one of themselves as leader, which requires votes from a majority of all Sentinels, and that leader runs the failover: promote a replica, reconfigure the others, and inform clients. Clients ask Sentinels for the current primary address. Deploy at least three Sentinels, on independent machines, so a majority survives one failure. See leader election for the underlying problem.
Redis Cluster
Redis Cluster shards data across multiple primaries. The key space is divided into 16384 hash slots. The slot of a key is CRC16(key) mod 16384. Each primary owns a subset of slots, and each primary can have replicas.
- A client sends a command to any node. If that node does not own the slot, it replies with a redirection (
MOVED slot host:port). Cluster-aware clients cache the slot-to-node map. - Resharding moves slots between nodes with key migration, while the cluster is online.
- Nodes exchange state using a gossip protocol, and replicas are promoted when a primary is detected as failed by a majority of primaries.
- Multi-key commands work only when all keys hash to the same slot. Hash tags allow this: only the part of the key inside
{...}is hashed, so{user42}:cartand{user42}:profileshare a slot.
Redis Cluster does not provide strong consistency. Replication between a primary and its replicas is asynchronous, so a primary that fails right after acknowledging a write can lose it, and a primary partitioned away from the majority of primaries stops accepting writes after a timeout.
Compared with consistent hashing, fixed slots make ownership an explicit table: moving a slot moves a known set of keys.
Memcached
Memcached is a multi-threaded in-memory cache. Its model is deliberately small:
- Keys map to opaque byte values, with a size limit (1 MB by default per item), and a TTL.
- Operations:
get,set,add,replace,delete,incr/decr,cas(compare-and-swap using a version token). - Memory is managed with slab allocation: memory is divided into size classes to avoid fragmentation, and each class has its own LRU.
- No persistence, no replication, no server-side clustering. Clients distribute keys across servers, typically using consistent hashing. Servers do not know about each other.
- Multi-threaded, so a single instance can use several cores.
Redis compared with Memcached
| Aspect | Redis | Memcached |
|---|---|---|
| Data types | strings, hashes, lists, sets, sorted sets, streams, and more | opaque strings |
| Persistence | RDB, AOF | none |
| Replication and failover | built in (replicas, Sentinel, Cluster) | none built in |
| Clustering | server-side (Cluster) | client-side sharding |
| Command execution | single-threaded | multi-threaded |
| Eviction | configurable policies (LRU/LFU approximations, random, TTL-based, or none) | LRU per slab class |
| Atomic operations | commands, transactions, Lua scripts | incr/decr, cas |
| Typical fit | cache plus data structures, counters, queues, leaderboards, rate limiting | simple, large, multi-threaded object cache |
Memcached suits a plain cache of serialized objects where multi-core efficiency and simplicity matter. Redis suits cases needing server-side structures, persistence, or replication.
Eviction when memory is full
Redis has a maxmemory limit and a maxmemory-policy. Policies include noeviction (writes fail), allkeys-lru, allkeys-lfu, allkeys-random, and volatile-* variants that only evict keys with a TTL. For a pure cache, an allkeys-* policy is typical. See cache eviction policies.
Interview questions
- Why is single-threaded Redis fast? Data is in memory, commands are short, there is no lock contention, and an event loop handles many connections. The trade-off is that one slow command delays every client.
- What is the difference between RDB and AOF? RDB is a periodic point-in-time snapshot: compact and quick to load, but changes since the last snapshot are lost on a crash. AOF logs each write and can lose at most about a second of data with per-second fsync, at the cost of a larger file and slower restart.
- How does Redis Cluster locate a key? It computes
CRC16(key) mod 16384to get the slot, and a slot-to-node table identifies the owner. A node that does not own the slot returns aMOVEDredirection. - Can a Redis failover lose data? Yes. Replication is asynchronous, so writes acknowledged by the old primary but not yet received by the promoted replica are lost.
