Redis
An in-memory data structure server that does far more than caching.
Introduction
Redis is a single-threaded, in-memory data store that keeps data in RAM for microsecond access. It is best known as a cache, but its rich data structures (strings, hashes, sets, sorted sets, streams) make it a Swiss-army knife for caching, rate limiting, queues, leaderboards, locks, and pub/sub.
Why it exists
Applications repeatedly need a fast shared place to put small, hot pieces of state — a cache entry, a counter, a session, a lock, a queue. A relational database is the wrong tool: too slow and too general. Redis gives you a shared, atomic, in-memory store with data structures that make these patterns one or two commands instead of hand-rolled logic.
Analogy
Redis is the kitchen's mise en place: a set of small, labeled containers within arm's reach holding exactly what you reach for constantly. It's not the pantry (the database) — it's the fast, organized surface you actually cook from.
How it works
Redis holds everything in memory and processes commands on a single thread, which means each command is atomic — no locks needed for INCR or SETNX. This is why Redis is a natural fit for counters, locks, and rate limiters.
Durability is optional and tunable: RDB snapshots periodically, AOF logs every write; you trade durability for speed. For scale, Redis offers replication (replicas for read scaling and failover), Sentinel (automatic failover), and Cluster (sharding across nodes by hash slot). Because it's in-memory, capacity is bounded by RAM and an eviction policy (e.g. allkeys-lru) decides what to drop when full.
Beyond key/value, the data structures are the point: hashes for objects, sorted sets for leaderboards and rate windows, streams for durable logs/queues, and pub/sub for fan-out messaging.
- 1
App sends a command over a persistent connection (from a pool).
- 2
Redis executes it on its single command thread — atomically.
- 3
Writes are optionally appended to AOF / captured by RDB for durability.
- 4
Writes replicate asynchronously to replicas for read scaling and failover.
- 5
If the primary dies, Sentinel/Cluster promotes a replica to primary.
Interactive
Architecture
Redis with replication and failover
Primary (writes)
Replicas (reads + standby)
Durability (optional)
Single-threaded command processing makes operations atomic; Sentinel promotes a replica if the primary fails.
In code
import { redis } from "@/lib/redis"
// Fixed-window limiter: 100 requests per user per minute.
export async function allow(userId: string): Promise<boolean> {
const key = `rl:${userId}:${Math.floor(Date.now() / 60000)}`
const count = await redis.incr(key) // atomic — no race across instances
if (count === 1) await redis.expire(key, 60)
return count <= 100
}// Add/update a score, then read the top 10 with ranks.
await redis.zadd("leaderboard", 4200, "user:42")
const top = await redis.zrevrange("leaderboard", 0, 9, "WITHSCORES")
const rank = await redis.zrevrank("leaderboard", "user:42") // 0-based positionIn the real world
Where you've seen this
A social app uses one Redis for several jobs: caching user profiles (hashes), rate limiting the API (INCR windows), a real-time leaderboard (sorted set), ephemeral sessions (strings with TTL), and fan-out notifications (pub/sub). Each of these would be awkward and slow in the primary database.
When to use it
Reach for it when
- Caching hot data and expensive computations.
- Atomic counters: rate limiting, quotas, metrics.
- Leaderboards, ranking, and time-window queries (sorted sets).
- Ephemeral state with TTLs: sessions, short-lived tokens.
- Lightweight queues/streams and pub/sub fan-out.
Avoid it when
- As the primary system of record for durable business data.
- Datasets far larger than available RAM (cost/eviction issues).
- Complex multi-entity queries, joins, and reporting.
- Strong cross-key transactional guarantees across a cluster.
Trade-offs
Advantages
- Microsecond latency; extremely high throughput.
- Atomic operations without app-side locking.
- Rich data structures that collapse common patterns into single commands.
- TTLs and eviction built in.
Disadvantages
- RAM-bound and comparatively expensive per GB.
- Durability is a trade-off; default configs can lose recent writes on crash.
- Cluster mode complicates multi-key operations (keys must share a slot).
- A single hot key can bottleneck one shard.
Redis trades durability and capacity for speed. You choose how durable (none / RDB / AOF everysec / AOF always) against how fast, and RAM cost against dataset size. Cluster gives horizontal scale but sacrifices easy multi-key atomicity. As a cache it's near-perfect; as a database it's viable only when you accept and configure for its durability and memory characteristics.
| Redis vs Memcached | Redis | Memcached |
|---|---|---|
| Data types | Strings, hashes, sets, sorted sets, streams | Strings only |
| Persistence | Optional (RDB/AOF) | None |
| Replication/HA | Yes (Sentinel/Cluster) | No (client-side sharding) |
| Best for | Versatile: cache, counters, queues, ranking | Pure, simple, multi-threaded caching |
Common mistakes
Watch out for
- Treating Redis as a durable database and losing data on restart.
- Big keys / big values that block the single thread (e.g. huge `KEYS` scans).
- Using `KEYS *` in production instead of `SCAN`.
- Ignoring eviction policy, so the cache silently drops needed keys.
- No connection pooling, exhausting connections under load.
Failure thinking
What breaks it
What happens if Redis goes down and you used it as a cache?
Reads fall through to the database, which can be overwhelmed (see cache stampede/cascading failure). Use short timeouts, treat errors as misses, coalesce origin calls, and protect the DB with a circuit breaker. If Redis held the only copy of something (a queue, a session), you lose it unless AOF/replication was enabled — which is why Redis-as-source-of-truth needs durability and failover configured.
One key becomes extremely hot (a celebrity's profile). What breaks?
In Cluster mode that key lives on one shard, so all traffic concentrates on a single node and single thread — a hot key bottleneck. Mitigate with client-side/local caching of that key, replicating reads to replicas, or splitting the value across multiple keys. Hot keys can't be solved by adding shards because a key maps to one slot.
Think like a senior
Senior Engineer Insight
Redis being single-threaded is a feature, not a limitation: it's why `INCR`, `SETNX`, and Lua scripts are atomic without distributed locks. Reach for a Lua script or `MULTI` when you need multiple commands to be atomic.
Senior Engineer Insight
The interview trap is 'use Redis' as a hand-wave. Say which data structure and why — a sorted set for windows, a hash for objects, a stream for a durable queue — and address hot keys and failure.
Remember
Redis is single-threaded, so single commands are atomic — no external lock needed.
Remember
In-memory means fast but RAM-bound and only as durable as you configure it.
Interview questions
Why is Redis a good fit for rate limiting?
Active recall
Check yourself
You need an eviction policy for a Redis cache holding hot application data with unknown access patterns. Which is the sensible default?
Practical challenges
Sliding-window limiter with sorted sets
Implement a sliding-window rate limiter in Redis and compare it to the fixed-window version.
Requirements
- Store request timestamps in a sorted set per key.
- On each request, drop entries older than the window and count the rest.
- Allow or deny based on the count, all atomically.
Constraints
- Use a Lua script or MULTI so the read-modify-write is atomic.
- Expire idle keys.
Acceptance criteria
- A burst spanning two fixed windows is correctly limited by the sliding window.
- Old timestamps are cleaned up so memory doesn't grow unbounded.
Edge cases
- Clock skew across instances.
- Very high request rate on one key.
Bonus
- Add the fixed-window version and demonstrate the edge-burst difference.
Reflection
- What's the memory cost of storing every timestamp, and how would a token bucket compare?
Architecture challenge
You're asked to use Redis for four things in one product: cache, session store, API rate limiter, and a job queue. For each, choose the data structure and the durability/eviction settings — noting that a cache wants eviction and no durability, while a job queue wants durability and no eviction. How do you keep these conflicting needs from fighting over one instance?
Flashcards
Summary
Redis is an in-memory, single-threaded data structure server whose atomic operations and rich types make it ideal for caching, counters, rate limiting, ranking, sessions, and lightweight queues. It trades durability and RAM cost for extreme speed, so treat it as a fast shared surface — durable only when you deliberately configure it to be.
Key takeaways
- Single-threaded ⇒ single commands are atomic ⇒ great for counters and locks.
- Pick the right data structure: sorted set for ranking/windows, hash for objects, stream for queues.
- In-memory ⇒ fast but RAM-bound; set an eviction policy for caches.
- Durability (RDB/AOF) and HA (Sentinel/Cluster) are opt-in — configure them if Redis holds anything you can't lose.
Your notes
Saved to this device