Notes
What it is
Redis is an in-memory key-value store where values are data structures: strings, hashes, lists, sets, sorted sets and more. Everything lives in RAM, so a read over the network takes a fraction of a millisecond. It can also persist to disk. After a licence change, the Linux Foundation forked it as Valkey, which speaks the same commands. AWS, Google and others run both for you.
- in-memory key-value store
- whose values are data
- structures, not just strings
- all data in RAM, optional
- persistence to disk
- Valkey: open-source fork,
- same commands and protocol
- managed: ElastiCache,
- MemoryDB, Redis Cloud
Data structures
The data structures are what make Redis more than a cache. Strings for cached values and counters. Hashes for objects with fields. Lists for simple queues. Sets for unique members. Sorted sets, where each member has a score, for leaderboards and time-ordered feeds. Streams for an append-only event log with consumer groups. HyperLogLog counts unique items in twelve kilobytes. And geo commands find things nearby.
String SET k v EX 60 cache, counter Hash HSET user:7 name A object fields List LPUSH / BRPOP simple queue Set SADD / SISMEMBER unique visitors Sorted ZADD / ZREVRANGE leaderboard Stream XADD / XREADGROUP event log HLL PFADD / PFCOUNT approx count Bitmap SETBIT / BITCOUNT daily actives Geo GEOSEARCH nearby drivers
Why it is fast
Why is it so fast? The data is in memory, so there is no disk on the read path. Commands run one at a time on a single thread, so there are no locks, and every command is atomic. Increment a counter from a thousand clients and none of the updates are lost. Newer versions use extra threads for network input and output. Pipelining sends many commands in one round trip. The flip side: one slow command blocks everyone.
- • data in RAM: no disk seek
- • one thread executes
- commands one at a time:
- no locks, each command
- is atomic
- • I/O threads for network
- (6.0+)
- • pipelining: send 100
- commands, one round trip
- • simple, compact encodings
TTL + eviction
Every key can have a time to live, after which it disappears. That is how caches stay fresh and sessions end. When memory reaches the limit you set, an eviction policy decides what goes. For a pure cache, all keys LRU drops the least recently used. If Redis also holds data you cannot lose, like queues or locks, use no eviction, so writes fail loudly instead of silently deleting data.
SET page:/home html EX 300
→ gone after 5 minutes
maxmemory 12gb
maxmemory-policy:
allkeys-lru cache: drop least
recently used
volatile-ttl drop soonest expiry
noeviction errors on write
(for queues, locks) Cache-aside
The pattern you will use most is cache-aside. The app asks Redis first. On a hit, it returns in under a millisecond. On a miss, it reads the database, then stores the result in Redis with a time to live. When the data changes, write the database and delete the cache key so the next read refills it. Add jitter to expiry times so thousands of keys do not expire together. The Cache building block goes deeper.
- 1. GET key from Redis
- 2. hit → return (sub-ms)
- 3. miss → read the database
- 4. SET key value EX ttl
- on update: write DB, then
- DELETE the key
- stampede guard: lock or
- jittered TTLs
More patterns
Other patterns are just a few commands. A rate limiter increments a counter per user per minute and sets it to expire, as in Concepts episode 30. A leaderboard adds points to a sorted set and reads the top ten in order, in logarithmic time even with millions of players. A simple lock sets a key only if it does not exist, with an expiry, and deletes it only if the token still matches. For locks that must be correct, see Concepts episode 31.
rate limit (fixed window): INCR rl:u42:202610241105 EXPIRE rl:u42:202610241105 60 leaderboard: ZINCRBY board 50 player:9 ZREVRANGE board 0 9 WITHSCORES lock: SET lock:job1 <token> NX PX 30000 (delete only if token matches)
Persistence
Redis can survive restarts. RDB writes a point-in-time snapshot every few minutes: compact and quick to load, but you can lose the writes since the last one. The append-only file logs every write, and with a flush every second you lose at most about a second. Many setups use both. A pure cache often uses neither, because it can always be rebuilt from the database.
- RDB: point-in-time snapshot
- every few minutes; compact,
- fast restart, lose minutes
- AOF: log of every write
- fsync everysec → lose at
- most ~1 s on crash
- common: both; or none for
- a pure cache
Replication
For availability, replicas copy the primary asynchronously and can serve reads. Sentinel, a small group of watcher processes, agrees when the primary is down, promotes a replica and tells clients the new address. Because replication is asynchronous, writes acknowledged just before a crash can be lost. That is fine for a cache, but worth saying if Redis holds anything important. MemoryDB on AWS adds a durable log for that case.
- replicas: async copy of the
- primary, can serve reads
- Sentinel (3+ processes):
- agree the primary is down,
- promote a replica, tell
- clients the new address
- async → writes acked just
- before a crash can be lost
Redis Cluster
When one machine's memory or CPU is not enough, Redis Cluster shards. Keys map to one of sixteen thousand three hundred and eighty-four hash slots, and each shard owns a range of slots, with its own replicas. Clients cache the slot map and are redirected if a slot has moved. Commands that touch several keys only work when they share a slot, so you put a common part in curly braces, a hash tag, to keep a user's keys together.
- 16,384 hash slots
- slot = CRC16(key) mod 16384
- each shard owns slot ranges,
- has its own replicas
- client caches the slot map;
- wrong shard → MOVED reply
- multi-key ops only within
- one slot: use hash tags
- {user:42}:cart, {user:42}:seen
Great at
Redis is great whenever many stateless app servers need fast shared state: caching database results, sessions and carts, rate limits and counters, leaderboards, short locks and deduplication, publish and subscribe to fan messages out to WebSocket servers, light queues with streams, nearby searches and online presence. One Redis often replaces several smaller systems.
- • cache in front of a DB
- • sessions and carts
- • rate limiting, counters
- • leaderboards (sorted sets)
- • short-lived locks, dedupe
- • pub/sub fan-out to sockets
- • lightweight queues (Streams)
- • geo lookups, presence
Where it hurts
Where it hurts. RAM is far more expensive than disk, so large data sets get costly. Asynchronous replication can lose recent writes. Because commands run one at a time, a single slow one, like listing all keys or deleting a huge set, freezes every client; use scan and unlink instead. A gigantic key or one wildly popular key overloads a single shard. And it should not be the only home for data you cannot afford to lose.
- • RAM is expensive per GB
- • async replication: may
- lose recent writes
- • one slow command blocks all
- (KEYS *, huge DEL, Lua)
- • big keys: a 1 GB hash
- • hot keys: one shard melts
- • cluster: no cross-slot ops
- • not a primary database for
- data you cannot lose
Use it when
Use Redis when you need sub-millisecond access to data that is rebuildable or short-lived, or when atomic counters, sorted sets and expiring keys make the problem easy. Avoid it as the system of record for data that must never be lost, when the data set is far larger than memory, or when you need flexible queries. Then it belongs in front of a real database, not instead of one.
- USE when
- you need sub-ms reads
- data is rebuildable or
- short-lived (TTL)
- you need atomic counters,
- sorted sets, rate limits
- AVOID when
- data set much larger than RAM
- data must never be lost
- you need queries or joins
Numbers
Numbers to have ready. Latency inside a region is a tenth of a millisecond to a millisecond. One instance handles around a hundred thousand simple operations a second, and over a million with pipelining. A value can be five hundred and twelve megabytes, but keep them small. Cluster has sixteen thousand three hundred and eighty-four slots. HyperLogLog uses twelve kilobytes with under one percent error. Aim for a cache hit rate above ninety percent.
latency in-region 0.1 - 1 ms ops per instance ~100k+/s with pipelining 1M+/s max value size 512 MB (keep values under ~100 KB) hash slots 16,384 HyperLogLog 12 KB, ~0.81% err AOF everysec loss up to ~1 s cache hit rate goal 90%+
Say it like this
How to say it. Redis as a cache-aside layer for product pages, ten minute time to live with jitter, least recently used eviction. The same cluster holds rate limit counters. Each shard has a replica and automatic failover. And if Redis is lost entirely, the service falls back to the database behind a circuit breaker, because the cache is an optimisation, not the source of truth. That last sentence is what interviewers listen for.
- "Redis as a cache-aside layer
- for product pages, TTL 10
- minutes with jitter, LRU
- eviction. Same cluster for
- rate-limit counters. A primary
- and replica per shard with
- failover. If Redis dies we
- fall back to the database
- with a circuit breaker."