The Redis facts that come up in backend and system design interviews, for Redis 7.4 and 8.x. Valkey, the BSD-licensed Linux Foundation fork of Redis 7.2.4, matches everything here except the modules built into Redis 8.
Core model
- In-memory server of typed values under string keys; commands run server-side, so each command is atomic.
- One main thread executes commands in an event loop (
epoll/kqueue). Background threads free memory (UNLINK) and fsync the AOF;fork()makes RDB snapshots and AOF rewrites;io-threads Noffloads socket reads, parsing and replies. - Consequence: single commands never race, but one slow command (
KEYS *,DELof a huge key, a long Lua script) blocks every client. - Licence: RSALv2/SSPLv1 since 7.4, AGPLv3 added as an option in Redis 8. Redis 8 bundles JSON, the Query Engine, time series, probabilistic types (Bloom, Cuckoo, Top-K) and vector sets.
Data types
| Type | Key commands | Cost | Typical use |
|---|---|---|---|
| String (≤ 512 MB) | SET, GET, INCR, SET NX PX, GETEX |
O(1) | cache blobs, counters, locks |
| Hash | HSET, HGET, HMGET, HINCRBY, HEXPIRE (7.4) |
O(1) per field | objects, carts |
| List | LPUSH, RPOP, BRPOP, LRANGE, LTRIM, LMOVE |
O(1) at ends | simple queues, recent items |
| Set | SADD, SISMEMBER, SINTER, SCARD |
O(1) add/check | tags, unique members |
| Sorted set | ZADD, ZINCRBY, ZRANGE … REV, ZRANK, ZRANGEBYSCORE |
O(log N) | leaderboards, schedules, sliding windows |
| Stream | XADD, XREADGROUP, XACK, XAUTOCLAIM, XTRIM |
O(1) append | durable event queues |
| HyperLogLog | PFADD, PFCOUNT, PFMERGE |
≤ 12 KB, ~0.81% error | unique counts |
| Bitmap | SETBIT, BITCOUNT, BITOP, BITFIELD |
1 bit per offset | daily active flags |
| Geo | GEOADD, GEOSEARCH |
O(log N) | nearby search |
LPUSH l a b cthenLRANGE l 0 -1givesc b a.SADDreturns how many members were new.- Sorted-set ties sort by member name.
ZREVRANKis zero-based from the top.
Expiry and eviction
SET k v EX 60 # TTL in seconds (PX for ms)
SET k v2 KEEPTTL # plain SET would remove the TTL
EXPIRE k 120 GT # NX | XX | GT | LT options (7.0+)
TTL k # -1 = no expiry, -2 = no such key
PERSIST k- Expired keys are removed lazily (on access) and actively (a sampling cycle,
hz 10). INCR,HSET,LPUSH,RENAMEkeep the TTL;SET,GETSETandDELclear it. Replicas wait for the primary’sDEL.
maxmemory-policy |
Evicts | Use |
|---|---|---|
noeviction (default) |
nothing; writes get OOM |
primary data |
allkeys-lru / allkeys-lfu |
any key | pure cache |
volatile-lru / volatile-lfu |
keys with a TTL | mixed cache + data |
volatile-ttl |
shortest remaining TTL | expiry-driven caches |
allkeys-random / volatile-random |
random | uniform access |
volatile-*with no TTL keys behaves likenoeviction.- LRU and LFU are approximate:
maxmemory-samples 5plus a 16-entry candidate pool. LFU uses a logarithmic 8-bit counter (lfu-log-factor 10) that decays (lfu-decay-time 1).OBJECT FREQneeds an LFU policy. - Watch
evicted_keys,expired_keys,keyspace_hits/keyspace_missesinINFO stats.
Caching patterns
| Pattern | Read | Write | Trade-off |
|---|---|---|---|
| Cache-aside | app checks cache, loads DB on miss, SET … EX |
update DB, then DEL key |
default; miss penalty, small stale window |
| Read-through | cache layer loads misses | (pairs with others) | needs a loader library |
| Write-through | from cache | write cache + DB synchronously | warm cache, slower writes |
| Write-behind | from cache | write cache, flush DB async | fast writes, loss risk |
- Invalidate with update DB, then delete; never update the cached value from the write path (writer races). TTL is the safety net; CDC or an outbox makes invalidation reliable.
- Stampede (hot key expires, everyone rebuilds): rebuild lock with
SET NX PX, stale-while-revalidate, probabilistic early refresh, TTL jitter. - Penetration (missing IDs): cache a short negative entry, Bloom filter. Avalanche (mass expiry or outage): jitter, HA, DB protection.
Persistence
| RDB | AOF | |
|---|---|---|
| What | forked point-in-time snapshot | log of write commands |
| Loss window | since last snapshot | always ≈ none, everysec ≈ 1 s (default), no ≈ OS flush |
| Size / restart | compact, fast | larger, replay (RDB preamble helps) |
| Maintenance | BGSAVE, save 3600 1 300 100 60 10000 |
BGREWRITEAOF; multi-part AOF with manifest (7.0+) |
fork()costs page-table copy time (latest_fork_usec) and copy-on-write memory; disable transparent huge pages, setvm.overcommit_memory=1, keep headroom.- Never auto-restart an empty primary with persistence off: replicas sync to the empty dataset.
Replication, Sentinel, Cluster
REPLICAOF host port;PSYNCwith replication ID + offset; partial resync fromrepl-backlog-size(1 MB default) or full resync (diskless by default since 7.0).- Replication is asynchronous: acknowledged writes can vanish on failover.
WAIT n ms,WAITAOF(7.2) andmin-replicas-to-writenarrow the window only. - Sentinel: ≥ 3 processes; SDOWN after
down-after-milliseconds, ODOWN whenquorumagree, failover needs a majority leader vote. Clients askSENTINEL get-master-addr-by-name. - Cluster: 16,384 slots,
slot = CRC16(key) mod 16384(foo→ 12182); bus port = data port + 10000; only DB 0.
| Reply | Meaning | Client action |
|---|---|---|
MOVED slot host:port |
slot owned elsewhere | retry there, refresh slot map |
ASK slot host:port |
slot migrating, key already moved | ASKING + retry once, keep map |
CROSSSLOT |
keys in different slots | hash tags or split the command |
TRYAGAIN |
multi-key op split by migration | retry later |
- Hash tag: only the text inside the first
{…}is hashed;{user:1000}:cartand{user:1000}:profileshare a slot. Never put everything under one tag.
Atomicity tools
| Tool | Atomic | Conditional logic | Round trips |
|---|---|---|---|
| Pipeline | no | no | 1 per batch |
MULTI/EXEC |
yes, no rollback | no (replies come at EXEC) |
1 if pipelined |
WATCH + MULTI |
optimistic; EXEC returns null on conflict |
yes, with retries | several |
Lua EVAL / Functions (7.0+) |
yes | yes | 1 |
- Queue-time error (unknown command) →
EXECABORT, nothing runs. Runtime error (WRONGTYPE) → that command fails, the others apply. - Lua: pass keys in
KEYS, values inARGV; Lua number → integer (3.99 → 3);false→ nil. Scripts overbusy-reply-threshold(5 s) make others getBUSY.
Locks and rate limits
-- acquire: SET lock:job <token> NX PX 30000 (reply OK or nil)
-- release only if we still own it:
if redis.call('GET', KEYS[1]) == ARGV[1] then
return redis.call('DEL', KEYS[1])
end
return 0- Not
SETNX+EXPIRE(crash in between leaves a lock forever); not a bareDEL(removes someone else’s lock after expiry). - Pauses can outlive the TTL: use fencing tokens at the resource for correctness. Redlock = majority of 5 independent primaries; Kleppmann’s critique targets timing assumptions.
| Limiter | Redis structure | Note |
|---|---|---|
| Fixed window | INCR + PEXPIRE on first hit (in Lua) |
2× burst at boundaries |
| Sliding log | sorted set of timestamps | exact; memory per request |
| Sliding counter | two window counters, weighted | approximate, cheap |
| Token bucket | hash tokens, ts refilled in Lua |
bursts + steady rate |
Messaging
- Pub/Sub: no storage, at-most-once; offline subscribers miss messages; slow ones hit
client-output-buffer-limit pubsub 32mb 8mb 60.SPUBLISH(7.0) for sharded channels. - Streams: IDs
ms-seq, consumer groups, pending entries list untilXACK,XAUTOCLAIMfor dead consumers, trim withMAXLEN ~.
Operations and memory
| Symptom | Check | Fix |
|---|---|---|
| Latency spikes | SLOWLOG GET, LATENCY DOCTOR, latest_fork_usec |
avoid O(N) commands, move persistence to replicas |
| Big keys | redis-cli --bigkeys, --memkeys, MEMORY USAGE k |
split into buckets, HSCAN, UNLINK |
| Hot keys | redis-cli --hotkeys (LFU policy) |
local cache, replica reads, key copies |
| Memory growth | INFO memory: used_memory, used_memory_rss, mem_fragmentation_ratio |
TTLs, listpack-friendly sizes, activedefrag yes |
| Key listing | never KEYS * |
SCAN 0 MATCH p:* COUNT 1000 |
- Compact encodings: hashes and sorted sets stay listpack up to 128 entries / 64-byte values; sets stay intset up to 512 integers. Strings:
int,embstr(≤ 44 bytes),raw. Check withOBJECT ENCODING.
Practise with the full question bank on the Redis topic page.