Why Redis stands out
System designs can involve a dizzying array of technologies, concepts, and patterns. Redis stands above the rest in terms of versatility. Instead of learning dozens of different technologies, you can learn a few useful ones deeply — which magnifies the chances you reach the level your interviewer expects.
Beyond versatility, Redis is great for its simplicity. It has a ton of features that resemble data structures you already know from coding — hashes, sets, sorted sets, streams — and they're easy to reason about in a distributed system once you know a few basics. While many databases involve optimizers and query planners, Redis has remained deliberately simple and good at what it does best: executing simple operations fast.
Keys → typed values in RAM.
16,384 slots · hash tags.
Cache · lock · zset · stream.
Hot keys · durability · no joins.
Redis basics
Redis is a self-described “data structure store” written in C. It keeps everything in memory and executes commands one at a time on a single thread — very fast and easy to reason about. The single-threaded design is deliberate: command execution never needs locks, and for operations this simple a single core is rarely the bottleneck. Newer versions offload I/O and background work to other threads, but the mental model is one command at a time, in order.
The core structure is a key-value store: every object is a value at a string key, and the value is where the data structure lives. When you create a sorted set, you're storing it as the value at whatever key you chose.
- Strings — counters, blobs, simple cache entries.
- Hashes — objects / dictionaries (product fields).
- Lists — queues, timelines (legacy patterns).
- Sets — unique membership.
- Sorted sets — leaderboards, priority queues.
- Streams — append-only logs with consumer groups.
- Geospatial — GEOADD / GEOSEARCH for proximity.
- Redis 8 adds Bloom filters, JSON, and time series in core; older versions used Redis Stack modules. Probabilistic structures (Bloom, HyperLogLog): Specialized data structures.
Beyond data structures, Redis supports Pub/Sub and Streams — partially standing in for Kafka or SNS/SQS in smaller designs. Key choice matters: keys may live on separate cluster nodes, so how you organize keys is how you scale.
Commands
Redis speaks RESP: commands travel over the wire close to how you'd type them. You can connect to an instance and run these as-is:
SET foo 1
GET foo # Returns 1
INCR foo # Returns 2
XADD mystream * name Sara surname OConnor
The full command set is surprisingly readable when grouped by structure. Sets support SADD, SCARD, SMEMBERS, SISMEMBER — close analogs to a programming-language set.
Infrastructure configurations
Redis runs as a single node, with an HA replica, or as a cluster. In cluster mode every key hashes to one of 16,384 hash slots, and each slot is assigned to a node. Clients cache the slot-to-node map, compute the slot from the key, and connect directly to the owning node. When you add a node, slots (and keys in them) migrate.
Think of hash slots like a phone book: if a slot moves during rebalancing or failover, the server replies MOVED and the client refreshes its map (e.g. via CLUSTER SHARDS). Nodes share cluster state via gossip, so every node knows the full slot map. The wrong node won't forward for you — clients aim for the correct node on the first try.
Redis clusters are surprisingly basic compared to most databases: with few exceptions, all data for a request must live on a single node. You scale by structuring keys. When two keys must live together, use hash tags: only the part inside {braces} is hashed, so {user:123}:posts and {user:123}:likes always share a slot — ready for a MULTI transaction across both.
Performance
Redis is really, really fast. A single node handles on the order of 100k writes per second. Commands execute in microseconds; over the network you see sub-millisecond reads. That makes some anti-patterns feasible: N+1 queries ruin a SQL database, but with Redis each command costs microseconds and you can pipeline or MGET to pay one round trip instead of a hundred. Still better to avoid N+1 — but it won't sink your design.
Speed is entirely a function of in-memory storage. Not every use case fits — but many interview paths do. Ballpark numbers: Numbers to know.
Redis as a cache
The most common deployment is as a cache. Cache keys are Redis keys; cached values are Redis values. The hash map distributes across cluster nodes — add nodes for capacity. Example: cache product:123 as a JSON blob or Hash with name, price, inventoryCount.
Use a TTL on each key — Redis guarantees you won't read a key after expiry. Expiration handles staleness, not memory pressure: by default Redis rejects writes when memory is full. Configure allkeys-lru so least-recently-used keys are discarded. Redis approximates LRU by sampling — plenty for a cache.
This doesn't solve the hot key problem — one key absorbing disproportionate traffic. Same issue on Memcached and DynamoDB. See Caching strategies for cache-aside, stampede, and invalidation patterns beyond “put Redis here.”
Redis as a distributed lock
Another common use: distributed locks when you need consistency during updates (Ticketmaster seat booking) or to prevent concurrent actions (Uber dispatch). Redis works because it's a shared server all app servers reach, and every command is atomic. Full ladder (when Redis is vs isn't the right rung): Dealing with contention.
SET lock:concert:343 my-token NX EX 30
NX makes the SET succeed only if the key doesn't exist — you own the lock or someone else does. EX 30 expires the key so a crashed process can't hold forever. my-token is a random value unique to you.
Release with a Lua script — don't blind DEL. Your lock may have expired and been re-acquired; deleting would remove someone else's lock:
if redis.call("GET", KEYS[1]) == ARGV[1] then return redis.call("DEL", KEYS[1]) end
This is pessimistic locking (grab before work). Redis also supports optimistic concurrency: WATCH a key, run MULTI/EXEC, and the transaction aborts if the watched key changed.
Redis for leaderboards
Sorted sets maintain ordered data queryable in log time — natural for leaderboards. High write throughput and low read latency help at scale where SQL struggles.
ZADD tiger_posts 500 "SomeId1"
ZADD tiger_posts 1 "SomeId2"
ZREMRANGEBYRANK tiger_posts 0 -6 # Keep top 5
ZADD sets a member's score, replacing if it exists — re-adding with a new like count moves rank. Negative indexes in ZREMRANGEBYRANK count from the top: ranks 0 through -6 clears everything except the top 5.
Redis for rate limiting
A fixed-window limiter: guarantee at most N requests over window W. On each request, INCR the counter for the current window. If count exceeds N, reject (429 + Retry-After). Set expiry only when INCR returns 1 — calling EXPIRE every request pushes the reset forward forever under steady traffic. Run INCR + EXPIRE in one Lua script.
For a sliding window, use a sorted set per user with timestamp as score: ZREMRANGEBYSCORE to drop old entries, ZCARD to count, ZADD if under N — atomically via Lua. See Design a rate limiter for the full interview walkthrough.
Redis for proximity search
Redis supports geospatial indexes natively:
GEOADD key longitude latitude member
GEOSEARCH key FROMLONLAT longitude latitude BYRADIUS radius unit
GEOSEARCH runs in O(N + log M) time: N elements in the grid-aligned bounding box, M within the exact radius. Redis uses geohashes under the hood (stored in a sorted set) — the log term is the seek. Geohash boxes are square and imprecise, so a second pass filters to the exact radius. Why that post-filter is mandatory, plus S2/H3 alternatives: Proximity search.
Redis for event sourcing
Streams are append-only logs similar to Kafka topics — building blocks for event-sourced designs where state is derived from an ordered log. Producers append with XADD; consumer groups (XREADGROUP, XCLAIM) coordinate who processes what.
Work queue flow: workers XREADGROUP, process, acknowledge. Pending entries track idle time — when a worker dies, idle time climbs until another worker XCLAIMs (or XAUTOCLAIM) and retries. Slow workers look like dead ones, so processing must be idempotent.
Redis for Pub/Sub
Streams are for consumers that need to catch up. When you only care about whoever's listening right now, use Pub/Sub — real-time broadcast without persistence. Useful for chat, live notifications, and decoupling producers from consumers.
PUBLISH channel message
SUBSCRIBE channel
Classic cluster Pub/Sub broadcast every message to every node — adding nodes didn't add capacity. Since Redis 7, sharded Pub/Sub (SPUBLISH/SSUBSCRIBE) routes each channel to the shard that owns its slot. A channel is just a name — nothing to create. Subscribers hold one connection per node and receive all subscribed channels over it.
Delivery is at-most-once: offline subscribers miss messages. Need persistence or replay? Use Streams, Kafka, or pair Pub/Sub with an outbox / queue (SNS→SQS pattern).
Can I roll my own Pub/Sub?
Some candidates recoil at native Pub/Sub because they assume a connection per channel (it isn’t). The typical proposal: store subscriber server addresses in a Redis set per topic, look them up on publish, and fan out directly to those servers.
Native Pub/Sub: client → Pub/Sub node → subscribers (two hops; connections already open). Homegrown: client → Redis lookup → client → each subscriber (three hops; often cold TCP). Homegrown also needs heartbeats/TTLs to prune dead servers from the map, while Pub/Sub drops a channel when the last subscriber disconnects. If the use case is Pub/Sub, use Pub/Sub.
Hot keys and remediations
Uneven key load causes the hot key problem. Example: 100-node ecommerce cache, items spread evenly — then one viral product matches the traffic of everything else combined. One server melts unless you were severely overprovisioned.
- Client-side caching — hot reads never reach Redis; accept short staleness.
- Key copies —
product:123:1…:10hash to different slots; readers pick at random; writes fan out. - Read replicas — multiply read capacity if clients are configured for replica reads; does nothing for write-hot keys.
In an interview, naming hot keys (+) and a remediation (++) signals production thinking. See Scaling writes and Scaling reads for the full ladders.
When not to use Redis
- Don't make Redis your system of record — async replication and persistence windows.
- Don't use it when the working set can't fit economically in RAM.
- Don't expect query flexibility — no joins, no cross-key queries; multi-key ops need one slot (hash tags help).
- Don't use streams instead of Kafka when you need durable, long-retention, many-consumer replay.
Cost and performance levers
Redis pattern picker
When Redis is the wrong hammer
- Primary system of record for money without careful persistence design.
- Huge datasets that don't fit memory economics.
- Complex ad-hoc queries → use Postgres/ES.
KEYS *in prod → use SCAN; avoid blocking commands on big collections.
Failure modes to mention
Call out at least one dependency failure (DB down, cache stampede, queue lag, region outage) and your mitigation (timeouts, retries with jitter, degraded mode, circuit breaker).
Interview Q&A by level
Practice saying these out loud for Redis. Interviewers grade clarity and judgment more than buzzwords.
Match depth to the bar: define → trade off → operate. Don't dump principal answers in an entry-level screen.
Wrapping up
Redis is powerful, versatile, and simple — capabilities built on familiar data structures, so scaling implications stay straightforward. You can go deep with an interviewer without Redis-internals trivia.
- Mental model: one command at a time, keys → typed values, slots → nodes.
- Default patterns: cache-aside + TTL,
SET NX EXlocks (with eyes open), zsets for ranks, streams for modest queues. - Name limits: durability, hot keys, single-slot multi-key ops.
- Pair with caching strategies for where caching fits; key technologies for the full toolbox map.
Using this for live fan-out? See Real-time updates for protocol choice and the two-hop model.