104 Redis Interview Questions and Answers (2026)

Redis has quietly become non-negotiable. As systems scale, more teams lean on it for caching, queues, locks, and real-time data, and interviewers now expect you to explain how it actually works, not just that you've used it. Walk in shaky on single-threading, persistence, or eviction, and it shows fast.
This is 104 questions with concise, interview-ready answers, code where it helps, worked from Junior to Mid to Senior. Start with the fundamentals and build toward the deep internals, so nothing catches you off guard on the day.
Q1.Why is Redis so fast despite being primarily single-threaded?
Redis is fast because it keeps all data in RAM, uses efficient data structures with mostly O(1) operations, and avoids the overhead that multi-threading and disk access impose, so the single thread is rarely the limiting factor.
Everything lives in memory: No disk seeks on the read/write path; persistence happens in the background.
Single-threaded avoids coordination cost: No locks, no mutexes, no context-switching or cache contention between threads for the core keyspace.
Optimized data structures: Hash tables, skip lists, and compact encodings (listpack, intset) give near-constant-time access with low memory overhead.
Efficient event-driven networking: Non-blocking I/O multiplexing plus a compact binary protocol (RESP) minimize per-request overhead.
Work stays close to the CPU: Simple, predictable code paths are cache-friendly, which matters more than raw parallelism for microsecond operations.
Q2.How does Redis differ from Memcached in terms of data types and persistence?
The core difference is richness: Memcached stores only opaque string/blob values and has no persistence, while Redis offers many server-side data structures and can persist data to disk for durability and restart recovery.
Data types:
Memcached: a single value type (a string/byte blob); any structure must be serialized client-side.
Redis: strings, hashes, lists, sets, sorted sets, streams, bitmaps, HyperLogLog, geo, and more, with atomic server-side operations on them.
Persistence:
Memcached: purely in-memory; data is lost on restart.
Redis: RDB snapshots and/or AOF append-only log allow recovery after restart, plus replication for HA.
Practical impact: Redis's types let you do things like leaderboards, queues, and counters atomically without round-trips; Memcached forces read-modify-write in the client.
Q3.What is Redis, and what are its primary use cases beyond simple caching?
Redis (REmote DIctionary Server) is an in-memory data-structure store used as a database, cache, and message broker. Because it exposes rich atomic data types over the network, it powers far more than caching: real-time counters, queues, leaderboards, sessions, rate limiting, and pub/sub messaging.
What it is:
An in-memory key-value store with optional persistence, replication, and clustering.
Values are structured (strings, hashes, lists, sets, sorted sets, streams, etc.), operated on atomically server-side.
Use cases beyond caching:
Session store: fast shared session state across app servers.
Leaderboards / ranking: sorted sets (ZADD, ZRANGE) give ranked queries out of the box.
Queues and streams: lists as simple queues, or Streams for consumer-group messaging.
Rate limiting and counters: atomic INCR with TTLs.
Pub/Sub: real-time messaging and fan-out notifications.
Distributed locks: coordination across services (e.g. Redlock pattern).
Approximate analytics: HyperLogLog for unique counts, bitmaps for presence.
Q4.Explain the difference between a Redis Set and a Sorted Set (ZSET). When would you choose one over the other?
Set and a Sorted Set (ZSET). When would you choose one over the other?A Set is an unordered collection of unique members; a Sorted Set is a collection of unique members each attached to a numeric score that keeps them ordered. Choose a ZSET whenever you need ranking or range-by-score queries, a plain Set when you only need membership and set algebra.
Set:
Unique, unordered members; O(1) SADD / SISMEMBER.
Supports set operations: SINTER, SUNION, SDIFF.
Use for tags, unique visitors, membership tests, relationships.
Sorted Set (ZSET):
Each member has a score; ordered by score then lexicographically.
Range/rank queries: ZRANGE, ZRANGEBYSCORE, ZRANK in O(log N).
Use for leaderboards, priority queues, time-ordered feeds, rate limiting by timestamp.
Choosing:
Need ordering, ranking, or "top N" / score ranges: ZSET.
Only need uniqueness and membership/intersection: Set (cheaper in memory and simpler).
Q5.Explain the difference between a Redis List and a Redis Set, and when would you use a Sorted Set (ZSET) instead of a List?
List and a Redis Set, and when would you use a Sorted Set (ZSET) instead of a List?A List is an ordered sequence that allows duplicates (good as a queue/stack); a Set is an unordered collection of unique members (good for membership). Reach for a Sorted Set when you need order driven by a value rather than insertion order.
List:
Ordered by insertion, duplicates allowed; push/pop at ends with LPUSH / RPOP.
Use for queues, stacks, activity streams, job pipelines.
Set:
Unordered, unique members; O(1) SADD / SISMEMBER plus union/intersection.
Use for tags, dedup, membership and relationship checks.
When a ZSET beats a List:
A List preserves only the order you pushed; a ZSET orders by an explicit score, so it stays sorted as items change.
Use a ZSET for leaderboards, priority queues, or feeds ranked by timestamp/score, where a List would need manual sorting.
Q6.How does the INCR command help implement atomic counters, and why is it safe under concurrency?
INCR command help implement atomic counters, and why is it safe under concurrency?INCR atomically increments the integer stored at a key by one and returns the new value. It is safe under concurrency because Redis executes commands one at a time on a single thread, so the read-modify-write happens as one indivisible operation with no interleaving.
Atomicity comes from the execution model:
Redis processes each command to completion before the next, so two clients incrementing simultaneously can never both read the same old value.
This eliminates the classic lost-update race you'd get with GET then SET from the client side.
Behavior details:
If the key doesn't exist, it's initialized to 0 before incrementing, so the first INCR returns 1.
Errors if the value isn't a valid 64-bit integer.
Related: INCRBY, DECR, DECRBY, and INCRBYFLOAT.
Typical uses: rate limiters, page-view counters, ID generators, all needing correct counts under high concurrency.
Q7.What is the difference between the SET command options NX, XX, EX, and PX?
SET command options NX, XX, EX, and PX?These are options on SET that control conditional writes and expiration: NX/XX gate whether the write happens based on key existence, while EX/PX attach a TTL in seconds or milliseconds.
Existence conditions:
NX: set only if the key does NOT already exist (used for locks and "create if absent").
XX: set only if the key already exists (update-only).
They are mutually exclusive; if the condition fails, SET returns nil.
Expiration options:
EX seconds: TTL expressed in seconds.
PX milliseconds: TTL expressed in milliseconds.
Also EXAT/PXAT (absolute Unix timestamp) and KEEPTTL (retain the existing TTL on overwrite).
They combine: e.g. SET lock 1 NX PX 5000 is the canonical atomic lock-with-timeout.
Q8.What does the TTL command return, and how do EXPIRE, PERSIST, and SETEX manage key lifetimes?
TTL command return, and how do EXPIRE, PERSIST, and SETEX manage key lifetimes?TTL returns the remaining lifetime of a key in seconds, and the family of expiration commands sets, removes, or combines a TTL with a write. Together they let you control exactly how long a key lives.
TTL return values:
A positive integer: seconds remaining.
-1: the key exists but has no expiration set.
-2: the key does not exist.
Use PTTL for millisecond precision.
EXPIRE:
Attaches a TTL (in seconds) to an existing key; PEXPIRE uses milliseconds.
Redis 7 adds flags NX, XX, GT, LT to conditionally update it.
PERSIST: Removes the TTL, making a volatile key permanent again; returns 1 if a TTL was cleared.
SETEX:
Sets a value and its TTL (seconds) atomically in one command; PSETEX is the millisecond variant.
Equivalent to SET key val EX seconds.
Note: overwriting a key with a plain SET clears its TTL unless you pass KEEPTTL.
Q9.What are good key-naming conventions in Redis, and why do namespaces matter?
Good Redis key names are structured, predictable strings that use a delimiter (commonly :) to build logical namespaces. Since Redis has one flat keyspace with no tables, naming conventions are how you organize, group, and safely manage keys.
Use a colon-delimited hierarchy: Pattern like object-type:id:field, e.g. user:1000:profile or session:abc123.
Why namespaces matter:
Enable scoped scans: SCAN with a pattern like user:* targets one logical group.
Avoid collisions across features/services sharing one instance.
Make it easy to reason about ownership, TTLs, and cleanup.
Keep keys short but descriptive: Very long keys waste memory at scale (millions of keys); overly cryptic keys hurt debuggability.
Avoid KEYS in production: Prefer SCAN; KEYS blocks the server. Good naming makes cursor-based iteration efficient.
Q10.What happens when Redis reaches its maxmemory limit and the policy is set to noeviction?
maxmemory limit and the policy is set to noeviction?With noeviction, Redis stops accepting writes that would increase memory and returns an error to the client, while reads and memory-freeing operations still succeed.
Writes fail: Commands that add data (SET, LPUSH, HSET, etc.) return an OOM error like OOM command not allowed when used memory > 'maxmemory'.
Reads and deletes still work: Read commands and operations that reduce memory (DEL, EXPIRE) continue to succeed.
Why use it: It is the safe default when Redis holds data you cannot afford to lose silently; the application must handle the error (retry, alert, or free space).
Caveat: Keys with TTLs still expire normally, so memory can drop over time, but Redis will not proactively evict to make room.
Q11.What is pattern-based subscription (PSUBSCRIBE) in Redis Pub/Sub, and when is it useful?
PSUBSCRIBE) in Redis Pub/Sub, and when is it useful?PSUBSCRIBE subscribes to channels by glob-style pattern rather than exact name, so one subscription can match many channels. It is useful when channel names encode structure and you want to listen to a whole family at once.
How it works:
PSUBSCRIBE news.* matches news.sports, news.tech, etc., using patterns with *, ?, and [...].
Matched messages arrive as a pmessage carrying both the pattern and the actual channel name.
When it's useful:
Multi-tenant or hierarchical channels (events.tenant42.*) where you don't know all channel names up front.
Monitoring or logging: subscribe broadly with one call instead of many exact SUBSCRIBE commands.
Caveats:
A message matching both an exact subscription and a pattern is delivered twice (once each).
Pattern matching adds CPU cost per publish, and it inherits Pub/Sub's at-most-once semantics.
Q12.How would you build a leaderboard in Redis, and why is a Sorted Set well suited for it?
Model each player as a member of a ZSET with their score as the sort key; the sorted set keeps everyone ranked automatically so reads of top-N and individual rank are fast.
Core operations:
Update a score with ZADD leaderboard 4500 player:42 or increment it with ZINCRBY.
Top 10 via ZREVRANGE leaderboard 0 9 WITHSCORES.
A player's rank via ZREVRANK, their score via ZSCORE.
Why a ZSET fits:
It maintains order continuously, so you never sort on read; inserts and rank lookups are O(log N).
Members are unique (one entry per player) and scores update in place.
Supports range queries: neighbors around a player, or all players in a score band.
Practical extras:
For time-boxed boards use a key per period (leaderboard:2024-06) with a TTL.
Tie-breaking: encode a secondary factor (e.g. earlier timestamp) into the score to make ordering deterministic.
Q13.How would you use Redis as a session store, and what are the advantages over storing sessions in a database?
Store each session under a key (typically the session ID) holding the session data with a TTL, and look it up on every request; Redis is a natural fit because it is in-memory, fast, and expires keys automatically.
Implementation:
Client gets a signed session ID cookie; server keys the data as session:<id>.
Store fields with a HASH (per-field access) or a serialized JSON string; set EXPIRE for idle timeout and refresh it on activity.
Advantages over a relational DB:
Speed: in-memory reads/writes on every request avoid disk-backed DB round trips.
Automatic expiry: TTL handles cleanup; no cron job sweeping stale rows.
Shared across app servers: any stateless instance can read the session, enabling horizontal scaling.
Trade-offs to acknowledge:
Durability: memory-first, so enable persistence (RDB/AOF) or replication if sessions must survive restarts.
It's best treated as ephemeral/soft state, not the system of record.
Q14.Redis is famously single-threaded. How does it handle high concurrency and achieve such high throughput?
Redis handles high concurrency with an event-driven, non-blocking I/O loop: a single thread multiplexes thousands of connections and executes each command extremely fast, so it never needs one thread per client.
Event loop with I/O multiplexing: Uses epoll/kqueue to watch many sockets at once, processing whichever are ready without blocking.
Concurrency is not parallelism: Many connections are in-flight simultaneously, but commands run one at a time; each is so short that clients rarely wait.
In-memory + O(1) operations: Most operations complete in microseconds, so the single thread churns through millions of ops per second.
Pipelining and multiplexing help throughput: Clients can batch commands to amortize round-trip latency, keeping the loop fed.
Caveat: one slow command (e.g. KEYS * on a large keyset) blocks everyone, since there's a single execution thread.
Q15.Beyond being in-memory, what architectural choices make Redis faster than a traditional disk-based database for simple key-value lookups?
Being in-memory is the biggest factor, but Redis also wins by stripping away the heavy machinery a general-purpose disk database needs: no query planner, no B-tree traversals, no transactional disk logging on the hot path, and a lightweight protocol.
Direct hash lookups, no query engine: A GET is a single hash-table probe; there's no SQL parser, optimizer, or execution planner between request and data.
No B-tree / index traversal: Disk DBs walk multi-level indexes and read pages; Redis addresses values directly in memory.
Persistence is off the hot path: RDB snapshots and AOF writes happen in the background or are buffered, unlike a disk DB's synchronous WAL flush per transaction.
Lightweight protocol and no per-request thread: RESP is trivial to parse and the event loop avoids thread setup, locking, and connection-pool overhead.
Simpler durability/consistency model: It doesn't pay for full ACID guarantees on every operation, trading some durability for speed.
Q16.What is the difference between Redis and Memcached, and when would you still choose Memcached today?
Both are in-memory key-value stores, but Redis is a rich data-structure server with persistence, replication, and many features, while Memcached is a deliberately minimal, multi-threaded cache for simple string/object blobs. Today you'd pick Memcached mainly for pure, high-scale caching of small opaque values where its simplicity and multi-threaded throughput shine.
Feature set:
Redis: many data types, persistence, replication, pub/sub, scripting, transactions, Cluster.
Memcached: just key-to-blob with expiration; no persistence, no replication.
Threading model:
Memcached is natively multi-threaded, so it can saturate many cores for simple get/set on one node.
Redis core is single-threaded (with I/O threads in 6.0+).
When to still choose Memcached:
Pure caching of small, uniform values with very high concurrency across many cores.
You want a dead-simple, low-overhead cache and don't need Redis's data types or persistence.
Its slab allocator can reduce memory fragmentation for fixed-size items.
Reality check: Redis covers most caching needs plus far more, so it's the default for new systems.
Q17.What is a HyperLogLog, and why would you use it instead of a standard Set for counting unique elements? What are the trade-offs in accuracy vs. memory?
HyperLogLog, and why would you use it instead of a standard Set for counting unique elements? What are the trade-offs in accuracy vs. memory?A HyperLogLog is a probabilistic data structure that estimates the number of distinct elements (cardinality) in a set using a tiny, fixed amount of memory. You use it instead of a Set when you only need an approximate unique count at massive scale and can't afford to store every member.
How it differs from a Set:
A Set stores every unique element, so memory grows with cardinality; a HyperLogLog stores only hash-derived statistics, not the elements themselves.
Because it discards the actual members, you can count uniques but never enumerate them or test membership.
Memory trade-off:
In Redis a HyperLogLog uses at most ~12 KB regardless of whether you counted 100 or 1 billion items.
A Set counting a billion items could consume gigabytes.
Accuracy trade-off:
The estimate has a standard error of about 0.81%, so it's approximate, not exact.
Fine for metrics like unique visitors; wrong choice when exact counts are required (e.g. billing).
Commands: Add with PFADD, read the estimate with PFCOUNT, and merge multiple with PFMERGE.
Q18.When storing a user profile object, why might you use a Redis Hash instead of a JSON string stored in a standard String key?
Hash instead of a JSON string stored in a standard String key?A Hash stores fields as native, individually addressable elements, so you can read or update a single field without fetching and re-serializing the whole object: a JSON String forces you to load, parse, mutate, and rewrite everything.
Partial reads and writes: With a Hash you use HGET / HSET on one field; with a String you must GET, parse JSON, edit, then SET the whole blob.
Atomic field operations: Numeric fields can be incremented server-side with HINCRBY, avoiding read-modify-write races.
Memory efficiency for small objects: Small Hashes use a compact listpack encoding, often smaller than a JSON string plus its key overhead.
When a String/JSON is still better:
If you always read the whole object at once, or need nested/complex structures, a JSON String (or the RedisJSON module) is simpler.
TTL is per-key, so you cannot expire individual Hash fields (older Redis); expiry applies to the whole object.
Rule of thumb: field-level access patterns favor a Hash; whole-object access favors a String.
Q19.What are Bitmaps and Bitfields, and in what scenario would they be more efficient than a Set?
Set?Bitmaps are Strings treated as an array of bits addressed by offset, and Bitfields let you pack multiple fixed-width integer counters into that same String: both are extremely space-efficient when your data maps to dense integer IDs.
Bitmaps:
Set/read a single bit with SETBIT / GETBIT, count set bits with BITCOUNT, combine keys with BITOP.
Classic use: daily active users, where bit at offset = user ID marks presence.
Bitfields:
Manipulate arbitrary-width integers (e.g. u8, i32) at bit offsets via BITFIELD, with overflow control.
Good for many small counters packed together (per-user rate limits, feature flags).
Why more efficient than a Set:
A Set of N integer IDs stores each element plus overhead; a Bitmap uses ~1 bit per possible ID, so a dense population of millions of users can fit in a few MB.
When it loses: sparse IDs (few users among a huge ID space) waste bits, and a Bitmap only answers presence/count, not "give me the members" efficiently.
Q20.Explain how a Sorted Set works internally, and when would you choose a ZSET over a standard List or Set?
Sorted Set works internally, and when would you choose a ZSET over a standard List or Set?A Sorted Set combines a hash table (member to score) with a skip list (ordered by score), giving O(1) score lookups and O(log N) ordered range/rank operations. Choose it over a List or Set whenever ordering by a numeric value matters.
Internal structure:
Hash table maps each member to its score for O(1) ZSCORE and uniqueness checks.
Skip list keeps members ordered by score, enabling O(log N) inserts and range queries like ZRANGEBYSCORE.
Small ZSETs use a compact listpack instead, upgrading to skiplist+hashtable past configured thresholds.
vs List: A List keeps insertion order only; reordering or "top N by score" would require scanning. A ZSET maintains sorted order automatically.
vs Set: A Set has no ordering or scoring. Add scores and you get ranking, priority, and range queries a Set cannot do.
When to choose a ZSET: Leaderboards, priority queues, sliding-window rate limiters (score = timestamp), and any "ordered by value" retrieval.
Q21.Explain the trade-offs of using HyperLogLog for unique visitor counts.
HyperLogLog for unique visitor counts.HyperLogLog is a probabilistic structure that estimates the number of unique items using a fixed ~12 KB regardless of cardinality, trading perfect accuracy (about 0.81% standard error) for enormous memory savings versus a Set.
How you use it: Add items with PFADD, read the estimate with PFCOUNT, merge structures with PFMERGE.
Advantages:
Constant memory (~12 KB) even for billions of uniques, versus a Set that grows with every member.
Mergeable: per-day HLLs can be combined for weekly/monthly uniques.
Trade-offs / limits:
It is an approximation (~0.81% error), so it is wrong for billing or exact counts.
You cannot retrieve or check individual members, only the estimated count.
No removals: you can only add and count.
When to choose it: High-cardinality counts where approximate is fine: unique visitors, distinct search terms; use a Set instead when you need exactness or the actual members.
Q22.What is the internal encoding of a Set (intset vs hashtable), and when does Redis switch between them?
intset vs hashtable), and when does Redis switch between them?A Redis Set uses one of two encodings: intset (a sorted array of integers) when all members are integers and the set is small, or hashtable (or listpack in newer versions for small sets) otherwise. Redis auto-upgrades and never downgrades within the key's lifetime.
intset:
Used when every member is an integer and count stays under set-max-intset-entries (default 512).
Compact, cache-friendly, kept sorted for binary-search lookups.
listpack: In Redis 7.2+, small non-integer sets use a listpack, bounded by set-max-listpack-entries and set-max-listpack-value.
hashtable: Used once a non-integer member appears (or the size/value limits are exceeded), giving O(1) membership at the cost of more memory.
Switch is one-way:
Once promoted to a hashtable, the encoding does not revert even if you remove members.
Inspect it with OBJECT ENCODING mykey.
Q23.How does Redis handle key expiration? Does it delete a key the exact millisecond it expires?
No, Redis does not delete a key at the exact millisecond it expires. It uses a combination of lazy (on-access) and active (periodic sampling) expiration, so a key may physically linger past its TTL until one of those mechanisms reaches it, though it is never served to clients once expired.
Lazy expiration:
When a key is accessed, Redis checks its TTL and deletes it if expired before responding.
An expired but untouched key wastes memory until accessed.
Active expiration:
A background cycle samples random keys from the expires dictionary ~10 times/second and evicts the expired ones.
If more than 25% of the sample was expired, it repeats immediately to catch up.
Correctness guarantee:
Logically the key is gone the instant its TTL passes: reads return nil even if bytes remain.
On replicas, keys expire only when the master sends a DEL/UNLINK, to keep data consistent.
Q24.What is the difference between the KEYS and SCAN commands, and why is KEYS generally banned in production?
KEYS and SCAN commands, and why is KEYS generally banned in production?Both find keys matching a pattern, but KEYS scans the entire keyspace in one blocking O(N) pass, while SCAN iterates incrementally in small batches via a cursor. KEYS is banned in production because it can block the single-threaded server for seconds on large datasets.
KEYS:
O(N) over all keys, executed atomically in one shot: the server processes nothing else until it finishes.
On millions of keys this stalls every client and can trigger timeouts.
SCAN:
Cursor-based: each call returns a batch plus the next cursor; you loop until the cursor is 0.
Each call is small and non-blocking, spreading work across many round trips.
Guarantees keys present for the whole scan are returned, but may return duplicates or miss keys added/removed mid-scan (weak consistency).
Variants HSCAN, SSCAN, ZSCAN iterate within a single collection.
Rule of thumb: never use KEYS outside a debug shell; use SCAN with a COUNT hint in application code.
Q25.When should you use UNLINK instead of DEL?
UNLINK instead of DEL?Use UNLINK instead of DEL when deleting large keys (big lists, sets, hashes, sorted sets), because UNLINK reclaims memory asynchronously in a background thread while DEL frees it synchronously and can block the main thread.
DEL: Removes the key and frees all its memory inline, so deleting a multi-million-element collection can block the server for milliseconds to seconds.
UNLINK:
Unlinks the key from the keyspace immediately (so it's instantly invisible) and defers the actual memory reclamation to a background thread.
For small keys it behaves essentially like DEL, freeing inline since the overhead of a thread isn't worth it.
Practical guidance: Prefer UNLINK as the default for potentially large keys; you can also set lazyfree-lazy-user-del yes to make DEL behave like UNLINK.
Q26.What is the time complexity of common Redis operations, and why should you avoid O(N) commands on large collections in production?
O(N) commands on large collections in production?Most core Redis operations are O(1) or O(log N), but some commands scan whole collections and are O(N). Since Redis executes commands on a single thread, an O(N) command over a huge collection blocks every other client for the duration, so they must be avoided or bounded in production.
Fast operations:
O(1): GET, SET, HGET, LPUSH, SADD, EXPIRE.
O(log N): sorted-set writes like ZADD and ZRANK.
Dangerous O(N) commands:
KEYS, SMEMBERS, HGETALL, LRANGE 0 -1, SORT scale with collection size.
On a million-element key they can stall the server for many milliseconds.
Why it hurts here specifically: The single-threaded model means one slow command delays all queued commands, spiking latency across all clients.
Mitigations: use SCAN/HSCAN family, paginate with LRANGE ranges, keep collections small, and watch the SLOWLOG.
Q27.What does the CONFIG GET/SET command allow you to do at runtime, and which settings can be changed without a restart?
CONFIG GET/SET command allow you to do at runtime, and which settings can be changed without a restart?CONFIG GET and CONFIG SET let you read and change most server configuration parameters at runtime without restarting Redis, so you can tune behavior on a live instance. Most directives are dynamic, but a few require a restart because they are read only at startup.
CONFIG GET: Reads current values, supports glob patterns, e.g. CONFIG GET maxmemory*.
CONFIG SET:
Applies a value immediately, e.g. CONFIG SET maxmemory 2gb or CONFIG SET maxmemory-policy allkeys-lru.
Changes are in-memory only; use CONFIG REWRITE to persist them back to redis.conf.
Commonly changed at runtime: maxmemory, eviction policy, save points, appendonly, slowlog and client limits.
Require a restart: Startup-only settings such as port, cluster-enabled, and io-threads cannot be changed live.
Q28.Compare RDB (Snapshotting) and AOF (Append-Only File) — what are the trade-offs regarding durability, file size, and recovery speed?
RDB (Snapshotting) and AOF (Append-Only File) — what are the trade-offs regarding durability, file size, and recovery speed?RDB takes point-in-time binary snapshots of the whole dataset, while AOF logs every write operation so it can replay them on restart. RDB gives compact files and fast recovery but risks losing recent writes; AOF gives better durability at the cost of larger files and slower recovery. Many production setups enable both.
Durability:
RDB: you lose everything since the last snapshot (minutes of data possible).
AOF: with appendfsync everysec you lose at most ~1 second; always loses almost nothing but is slower.
File size:
RDB is compact (a compressed binary dump).
AOF is larger since it stores a command history, though rewrites compact it.
Recovery speed:
RDB loads fast: it just reconstructs from the dump.
AOF is slower: it replays commands, though modern AOF starts from an RDB base to speed this up.
Operational impact: RDB forking for large datasets can cause a memory/CPU spike; AOF writes add ongoing I/O.
Best practice: Enable both: RDB for fast backups/restore, AOF for stronger durability.
Q29.What is "Hybrid Persistence," and why would a developer enable both RDB and AOF?
RDB and AOF?Hybrid persistence is a mode (enabled with aof-use-rdb-preamble yes) where an AOF rewrite writes a compact RDB snapshot as the file's preamble, followed by the incremental AOF commands accumulated since. It combines RDB's fast, compact loading with AOF's fine-grained durability.
RDB alone: fast restart, small files, but risks losing minutes of data: Snapshots happen at intervals, so anything after the last snapshot is lost on crash.
AOF alone: durable, but slow to load and large: Replaying millions of commands at startup is slow, and the file grows large.
Hybrid gets the best of both: The RDB preamble loads quickly like a snapshot; the trailing AOF tail supplies recent writes for near-zero data loss.
Why enable both: you want fast recovery AND minimal data loss, without choosing one tradeoff.
Q30.What is the difference between Pipelining and Transactions (MULTI/EXEC), and when would you choose one over the other?
MULTI/EXEC), and when would you choose one over the other?Pipelining is purely a network optimization (send many commands without waiting for each reply); transactions with MULTI/EXEC add atomicity and isolation, queuing commands so they execute as one uninterrupted unit.
Pipelining = throughput, not atomicity:
The client sends N commands back-to-back and reads N replies later; it saves round-trip time (RTT) only.
Other clients' commands can interleave between the pipelined ones: no isolation.
Transactions = atomicity + isolation:
Commands between MULTI and EXEC are queued, then run sequentially with no other client interleaved.
No rollback: a runtime error on one command doesn't undo the others, unlike SQL transactions.
Use WATCH for optimistic locking (check-and-set): EXEC aborts if a watched key changed.
They combine well: Clients typically pipeline the whole MULTI ... EXEC block, so you get atomicity plus fewer round trips.
When to choose which:
Just need speed for independent commands: pipeline.
Need a group of writes to be all-or-interleave-free: transaction (or a Lua script, which is often simpler and also atomic).
Q31.What is Redis Pipelining, and how does it reduce latency?
Pipelining lets a client send multiple commands to Redis without waiting for each individual reply, then read all replies in bulk; it slashes latency by eliminating per-command network round trips.
The problem it solves: Normally each command costs one round-trip time (RTT); 1000 commands = 1000 RTTs, dominated by network latency, not Redis's speed.
How it works:
The client writes many requests to the socket at once; Redis processes them in order and buffers the responses.
The client reads all replies afterward, so the whole batch costs roughly one RTT plus server processing.
Caveats:
No atomicity or isolation: it's just batching (unlike MULTI/EXEC).
Keep batches bounded (e.g. a few thousand): huge pipelines grow server reply buffers and memory.
Q32.How does the SLOWLOG help you diagnose performance problems in Redis?
SLOWLOG help you diagnose performance problems in Redis?The SLOWLOG records commands whose execution time exceeded a configured threshold, letting you pinpoint the specific slow operations that are blocking Redis's single-threaded command loop.
What it measures: Only the command's execution time inside Redis, not network or I/O wait, so it isolates true server-side cost.
Configuration:
slowlog-log-slower-than sets the threshold in microseconds (e.g. 10000 = 10ms).
slowlog-max-len caps how many entries are retained.
Reading it:
SLOWLOG GET 10 shows recent entries with timestamp, duration, and the exact arguments.
SLOWLOG RESET clears the log.
What it typically reveals: O(N) commands on big collections (KEYS, SMEMBERS, large LRANGE, SORT) that block everything else while they run.
Q33.What kind of information does the INFO command expose, and how do you use it for monitoring?
INFO command expose, and how do you use it for monitoring?The INFO command returns a large set of server metrics grouped into sections, giving you a real-time snapshot of memory, clients, persistence, replication, and workload that you scrape for monitoring and alerting.
Key sections:
Memory: used_memory, maxmemory, and mem_fragmentation_ratio (fragmentation health).
Stats: instantaneous_ops_per_sec, plus keyspace_hits vs keyspace_misses for hit ratio.
Clients: connected_clients and blocked_clients.
Replication: role, connected replicas, and master_repl_offset lag.
Persistence: RDB/AOF status and last save success.
How to use it:
Request a single section (INFO memory) to reduce noise.
Exporters (e.g. redis_exporter) parse INFO into Prometheus metrics for dashboards and alerts.
Watch derived signals: hit ratio dropping, memory nearing maxmemory, rising eviction/expiry counts.
Q34.How do you benchmark Redis performance, and what factors most affect latency?
You benchmark Redis with the bundled redis-benchmark tool (or memtier_benchmark), driving realistic commands and concurrency; latency is dominated far more by network round trips, payload size, and command complexity than by raw Redis throughput.
Running a benchmark:
redis-benchmark -n 100000 -c 50 -t get,set sets request count, concurrency, and command mix.
Use -P to test pipelining and -d to vary value size, matching your real workload.
Measure latency percentiles directly with redis-cli --latency.
Factors that most affect latency:
Network RTT: often the biggest factor; run client near the server and use pipelining.
Command complexity: O(N) commands scale with data size and block the single thread.
Payload size: large values cost bandwidth and serialization time.
Persistence and forks: RDB save / AOF rewrite can cause pauses.
Caveat: Benchmark from the client's real location with real command patterns; localhost numbers overstate production throughput.
Q35.How does Lua scripting in Redis ensure atomicity?
A Lua script runs atomically because Redis executes it in its single-threaded engine as one blocking unit: no other command or script runs until the script finishes.
Single-threaded execution: While EVAL runs, Redis processes nothing else, so the script sees a consistent snapshot and no client can interleave.
Read-then-write logic is safe: You can read a value, branch on it, and write back within the same atomic window: impossible to race.
The cost of atomicity: A long-running script blocks the whole server, so scripts must be fast; lua-time-limit governs when Redis will accept SCRIPT KILL.
Determinism matters: Historically scripts had to be deterministic (for replication); modern Redis uses effects-based replication, propagating the actual writes rather than the script.
Q36.How does the WATCH command facilitate optimistic locking in Redis? What happens to a transaction if a watched key is modified by another client?
WATCH command facilitate optimistic locking in Redis? What happens to a transaction if a watched key is modified by another client?WATCH implements optimistic locking (check-and-set): you mark keys to watch, and if any of them change before your EXEC, the whole transaction is aborted so you can retry. No locks are actually held.
The flow:
WATCH key the keys you plan to base decisions on.
Read them and compute your change.
MULTI, queue commands, then EXEC.
If a watched key was modified: EXEC returns nil (aborted) and none of the queued commands run; the client typically retries the whole cycle.
Optimistic, not pessimistic: It assumes conflicts are rare: no waiting or blocking, just detect-and-retry, which scales well under low contention.
Notes: UNWATCH clears watches; EXEC and DISCARD also clear them automatically.
Q37.What are Redis Functions, and how do they improve upon traditional Lua scripting (EVAL)?
EVAL)?Redis Functions (introduced in Redis 7) are server-side logic registered as named libraries that persist in the database, replacing the ad-hoc, script-per-call model of EVAL. They are managed with the FUNCTION command family and called with FCALL.
First-class, persistent logic: Functions are loaded once via FUNCTION LOAD, stored in the dataset, and replicated/persisted, so they survive restarts and reach replicas: unlike scripts that live only in a runtime cache.
Called by name: FCALL myfunc is clearer than juggling SHA1 digests from EVALSHA, and avoids re-sending script bodies.
Libraries group related functions: One library can register many functions and share helper code, encouraging reusable application-side APIs.
Same atomicity model: They execute atomically in the single-threaded engine exactly like Lua scripts.
Better operational story: FCALL_RO flags read-only functions for replicas, and function metadata is introspectable via FUNCTION LIST.
Q38.Why is Lua scripting often preferred over standard Redis transactions for complex logic?
Lua scripting is preferred for complex logic because it can make decisions server-side: it can read a value and branch on it within the same atomic execution, which MULTI/EXEC cannot do.
Conditional logic: Transactions queue commands blindly before EXEC, so you can't use one command's result to decide the next; Lua can do if/loops.
Fewer round trips: Multi-step read-modify-write logic runs in a single call instead of client round trips plus a WATCH/retry loop.
Avoids optimistic-lock retries: Because the script is atomic, there's no contention window that forces WATCH-based retries.
Real error handling: A script can inspect results and abort early (return redis.error_reply(...)), whereas a transaction runs every queued command regardless.
Caveat: The script blocks the server while it runs, so keep it short and O(reasonable).
Q39.Why are Lua scripts in Redis considered atomic, and how do they differ from a standard Redis Transaction (MULTI/EXEC)?
MULTI/EXEC)?Both are atomic because Redis is single-threaded, but a Lua script is a single opaque unit of computation with control flow, while MULTI/EXEC is just a queued batch of independent commands.
Shared atomicity source: Neither allows another client to interleave: the engine runs the whole unit before doing anything else.
Logic vs blind batching: Lua can read intermediate values and branch; a transaction commits to its commands at queue time and can't react to results.
Error behavior: In a transaction a runtime-failing command is skipped and the rest still run; in Lua you can detect the failure and stop or return an error.
Optimistic locking: Transactions pair with WATCH for check-and-set; Lua needs no such thing because it's already atomic.
Neither rolls back: Effects already applied before an error are not undone in either mechanism.
Q40.What happens when Redis reaches its maxmemory limit? Describe the different eviction policies.
maxmemory limit? Describe the different eviction policies.When memory usage hits maxmemory, Redis applies the configured maxmemory-policy to decide whether to evict keys or reject writes. The policy determines which keys (if any) are removed to make room.
No-eviction: noeviction: writes that need memory return an error; reads still work. Safe for durable data stores.
LRU policies (least recently used):
allkeys-lru: evict least-recently-used across all keys.
volatile-lru: same but only among keys with a TTL set.
LFU policies (least frequently used, Redis 4+): allkeys-lfu / volatile-lfu: evict by access frequency, better for skewed hot/cold access patterns.
Random policies: allkeys-random / volatile-random: evict a random key (optionally only those with TTL).
TTL-based: volatile-ttl: evict keys with a TTL, preferring the shortest remaining time-to-live.
Key detail on volatile-* policies: If no keys have a TTL, they behave like noeviction and writes fail. Also note LRU/LFU are approximate (sampled), not exact, for performance.
Q41.Explain the difference between the allkeys-lru and volatile-lru eviction policies.
allkeys-lru and volatile-lru eviction policies.Both evict least-recently-used keys, but they differ in which keys are eligible: allkeys-lru considers every key, while volatile-lru only considers keys that have a TTL set.
allkeys-lru:
Any key in the keyspace can be evicted, whether or not it has an expiry.
Best when Redis is used purely as a cache and every key is disposable.
volatile-lru:
Only keys with an expiry set are candidates; keys without a TTL are never evicted.
Best for a mixed workload where some keys are persistent data and TTL marks the cacheable ones.
Shared caveat for volatile policies: If no keys have a TTL, volatile-lru has nothing to evict and behaves like noeviction, returning errors on writes.
Q42.What is the difference between LRU and LFU eviction in the context of Redis?
LRU evicts by recency (how long since a key was last accessed) while LFU evicts by frequency (how often a key is accessed), so LFU better protects popular keys that are used regularly even if not touched most recently.
LRU: recency-based:
Evicts the key untouched for the longest time.
Weakness: a rarely-needed key accessed once during a scan looks 'recent' and survives, while a hot key can be evicted after a quiet gap.
LFU: frequency-based:
Evicts the key with the lowest access count, keeping consistently popular keys.
Added in Redis 4.0 as allkeys-lfu and volatile-lfu.
When to choose which: LFU shines when access patterns are skewed (a stable set of hot keys); LRU is fine for workloads dominated by recency.
Q43.Both Redis Streams and Pub/Sub can be used for messaging. What are the fundamental differences in terms of data persistence and consumer acknowledgment?
Pub/Sub is fire-and-forget: messages are pushed to whoever is connected and then discarded, with no storage or acknowledgment. Streams are a persistent, append-only log where messages are retained and consumers explicitly acknowledge processing.
Persistence:
Pub/Sub keeps nothing: a subscriber offline at publish time never sees the message.
Streams store entries in the keyspace (and in RDB/AOF), so consumers can read history and catch up later.
Acknowledgment and delivery:
Pub/Sub has no ack and at-most-once delivery; a crash mid-processing loses the message.
Streams track a Pending Entries List and require XACK, enabling at-least-once delivery and reprocessing of failures.
Consumption model:
Pub/Sub broadcasts every message to all subscribers of a channel.
Streams support both fan-out (independent readers) and work-queue distribution via consumer groups.
Rule of thumb: Use Pub/Sub for ephemeral, low-latency notifications; use Streams when you need durability, replay, or guaranteed processing.
Q44.What are keyspace notifications in Redis, and what are their limitations for building reliable event-driven systems?
Keyspace notifications make Redis publish events over Pub/Sub whenever keys change (set, expired, deleted, etc.), letting clients react to data changes. Because they ride on Pub/Sub, they inherit its fire-and-forget nature and are unreliable for guaranteed event processing.
What they are:
Enabled via notify-keyspace-events config, which selects event classes (generic, expired, evicted, etc.).
Two channel styles: keyspace events (__keyspace@0__:mykey reporting the command) and keyevent events (__keyevent@0__:expired reporting the affected key).
Reliability limitations:
Delivered over Pub/Sub, so a disconnected or lagging subscriber misses events permanently: no persistence, no replay, no acks.
Expired-key events fire when Redis actually removes the key (lazily on access or during background cycles), so they can be delayed well past the TTL.
On a cluster, events are node-local, so a subscriber must connect to every node to see all events.
Practical guidance: Fine for cache invalidation hints or best-effort reactions; for guaranteed processing, write changes to a Stream instead.
Q45.How can you use Redis Lists as a simple queue, and what do the blocking commands BLPOP/BRPOP provide?
BLPOP/BRPOP provide?A Redis List is a doubly-linked sequence you push and pop from either end, so producers LPUSH and consumers RPOP (or vice versa) to form a FIFO queue. The blocking variants BLPOP/BRPOP let a consumer wait for work instead of busy-polling.
Basic queue pattern:
Producer: LPUSH queue job; consumer: RPOP queue for FIFO ordering.
Push and pop are O(1) at the ends, so throughput stays high.
What blocking commands add:
BRPOP queue 0 blocks until an item exists (0 = wait forever), avoiding CPU-wasting poll loops.
You can pass multiple keys: BRPOP q1 q2 5 returns from whichever has data first, enabling priority queues.
They return the key name plus the value, and honor a timeout (in seconds).
Limitations:
No acknowledgement: a crashed consumer loses the popped job. Use BRPOPLPUSH/BLMOVE into a processing list for reliability, or use Streams for real durability.
No consumer groups or replay: each item goes to exactly one consumer.
Q46.What are the basic Redis Streams commands (XADD, XREAD, XRANGE), and how is a stream structured internally?
XADD, XREAD, XRANGE), and how is a stream structured internally?Streams are an append-only log of entries, each with an auto-generated ID and a set of field-value pairs. XADD appends, XRANGE reads by ID range, and XREAD reads new entries (optionally blocking) after a given ID.
XADD (append):
XADD mystream * temp 21 humidity 60: the * tells Redis to generate the ID.
IDs are <millisecondsTime>-<sequence>, monotonically increasing so ordering is guaranteed.
XRANGE / XREVRANGE (query a range): XRANGE mystream - + reads all entries; - and + are min/max IDs, with a COUNT option to page.
XREAD (consume new data): XREAD BLOCK 0 STREAMS mystream $: $ means "only entries added after now", and BLOCK 0 waits indefinitely.
Internal structure:
Backed by a radix tree (rax) keyed by entry ID, with entries packed into listpack macro-nodes for compact memory.
This gives efficient ordered range access and cheap appends, unlike Lists which have no ID indexing.
Q47.What delivery guarantee does Redis Pub/Sub provide, and why is it considered 'at-most-once'?
Redis Pub/Sub provides at-most-once delivery: a published message is pushed only to clients currently subscribed at that instant, and is never stored or retried. If no one is listening, the message is simply dropped.
Fire-and-forget model:
PUBLISH delivers to active subscribers of the channel and returns the count reached, then forgets the message.
There is no persistence, no acknowledgement, and no replay.
Why 'at-most-once':
A subscriber that is disconnected, slow, or reconnecting misses everything published during that gap.
A message is delivered zero or one time to each subscriber, never redelivered, hence at-most-once.
When it matters:
Fine for ephemeral notifications (live metrics, cache invalidation hints) where loss is tolerable.
For durability, ordering, and replay, use Redis Streams with consumer groups instead.
Q48.What are the trade-offs of using Redis as a primary database versus just a cache?
As a cache Redis is a fast, disposable copy of data that lives authoritatively elsewhere; as a primary database it is the source of truth. The trade-offs center on durability, memory cost, and data-modeling limits versus raw speed.
Durability risk:
Redis is in-memory; even with AOF (appendfsync everysec) or RDB snapshots you can lose the last window of writes on crash.
As a cache, loss is harmless (rebuild from the DB); as primary store, it can mean permanent data loss.
Memory cost: Everything must fit in RAM, which is far more expensive per GB than disk. Caches hold a hot subset; a primary DB must hold all data.
Query and modeling limits:
No rich ad-hoc queries, joins, or multi-key ACID transactions like a relational DB; you design access patterns around keys.
Modules (RedisJSON, RediSearch) narrow this gap but add complexity.
Why choose primary anyway:
Sub-millisecond latency and high throughput for well-bounded data (sessions, leaderboards, real-time counters).
Best when the dataset fits in memory and eventual/tuned durability is acceptable.
Q49.How would you use Redis to track the daily active status of millions of users with minimal memory footprint?
Use a bitmap: one Redis String where each bit position represents a user ID, set to 1 when that user is active for the day. Millions of users fit in a few megabytes, and you can count actives with a single command.
Structure:
One key per day, e.g. active:2024-06-01, with user ID as the bit offset.
SETBIT active:2024-06-01 12345 1 marks user 12345 active.
Memory footprint: 1 bit per user: 10 million users is ~1.25 MB per day, versus megabytes-per-thousand for a Set of IDs.
Analytics operations:
BITCOUNT active:2024-06-01 gives the daily active count.
BITOP AND / OR across day-keys computes retention or weekly-active (e.g. AND two days for users active both days).
Caveat: Bitmaps require dense, integer user IDs. If IDs are sparse or non-numeric, map them to a compact index first, or use HyperLogLog when you only need approximate unique counts.
Q50.What is the difference between a List and a Sorted Set (ZSET) for implementing a message queue or leaderboard?
ZSET) for implementing a message queue or leaderboard?Use a List for FIFO/LIFO queues where order is insertion-based, and a ZSET (sorted set) when items must be ordered by a numeric score, as in a leaderboard or a delay/priority queue.
List: ordered by insertion:
Push/pop from either end with LPUSH, RPUSH, LPOP, RPOP; blocking variants BLPOP/BRPOP enable a worker queue.
O(1) at the ends but no random reordering; duplicates allowed.
Best for simple job queues where you just want the next-in item.
Sorted Set: ordered by score:
Each member is unique and carries a float score; ZADD inserts/updates, ZRANGE/ZREVRANGE read ranked slices, ZRANK gives position.
Ideal for leaderboards (score = points) or scheduled queues (score = timestamp, pop due items with ZRANGEBYSCORE).
Operations are O(log N), and updating an existing member's score is cheap.
Rule of thumb: Order determined by when it arrived: List. Order determined by a value (points, time, priority) and members are unique: ZSET.
Q51.How would you implement a rate limiter using Redis? What data structures and commands would you use?
A Redis rate limiter counts requests per key (user/IP) within a time window and rejects once a threshold is exceeded; the classic approaches are a fixed-window counter with INCR + EXPIRE, or a sliding-window log using a sorted set.
Fixed window counter (simplest):
Key like rate:user:123:1699999 (bucketed by time); INCR it and set EXPIRE on first hit.
Reject if the returned count exceeds the limit; cheap and O(1) but allows bursts at window boundaries.
Sliding window log (more accurate):
Store each request timestamp in a ZSET; ZREMRANGEBYSCORE prunes entries older than the window, then ZCARD counts what remains.
Smooth, no boundary bursts, but more memory and commands per request.
Atomicity matters: Wrap the read-decide-write in a Lua script or MULTI/EXEC so concurrent requests can't race past the limit.
Q52.What is the cache-aside pattern, and how is it typically implemented with Redis?
Cache-aside (lazy loading) means the application checks Redis first, and only on a miss reads the database and populates the cache; the app, not Redis, owns the caching logic.
Read path:
Look up the key in Redis (GET).
On hit, return it.
On miss, query the DB, then SET the value with a TTL and return it.
Write path: Write to the DB, then invalidate (DEL) or update the cache key so the next read repopulates it.
Why it's popular:
Only requested data is cached, so memory holds the hot set.
Cache failure degrades gracefully: you fall back to the DB.
Pitfalls:
Stale data between DB write and invalidation; mitigate with sensible TTLs.
Thundering herd / cache stampede when a hot key expires; mitigate with locks or staggered TTLs.
Q53.What are Redis logical databases (SELECT / numbered DBs), and what are their limitations especially in Cluster mode?
SELECT / numbered DBs), and what are their limitations especially in Cluster mode?Logical databases are a fixed set of numbered namespaces (0-15 by default) within a single Redis instance, selected per-connection with SELECT; they share the same process and memory and are largely a legacy feature.
What they are:
Numbered keyspaces on one server; SELECT 1 switches the connection's active DB, count set by databases in config.
Useful for crude separation (e.g. cache in DB0, jobs in DB1) or FLUSHDB on one without touching others.
Limitations:
Not isolated: they share memory, CPU, and a single-threaded event loop, so no per-DB resource control or auth (until ACLs).
Cross-DB operations are limited; discouraged in modern usage in favor of key prefixes or separate instances.
Cluster mode: only DB 0:
Redis Cluster supports a single database (0); SELECT on any other index errors out.
Reason: data is sharded across nodes by key slot, and multiple logical DBs would complicate slot mapping.
Q54.How does Redis handle authentication and access control? Explain the difference between requirepass and ACLs.
requirepass and ACLs.Redis authenticates connections with the AUTH command; the old model was a single shared password (requirepass), while ACLs (from Redis 6) add multiple named users with fine-grained permissions.
requirepass (legacy, single password):
Sets one global password; every client sends AUTH <password> and then has full access.
No concept of users, no way to restrict which commands or keys a client can touch.
Internally it now maps to the default ACL user's password.
ACLs (Redis 6+, fine-grained):
Define multiple users with ACL SETUSER, each with its own password(s).
Restrict per user: which commands/categories (+get, -flushall, +@read) and which key patterns (~cache:*) and channels.
Clients authenticate with AUTH <user> <password>; enables least-privilege roles.
Key difference: requirepass = all-or-nothing single secret; ACLs = multiple identities with scoped command and key permissions.
Always pair auth with TLS: Passwords travel in the clear otherwise; enable TLS on untrusted networks.
Q55.What is 'protected mode' in Redis, and why does it exist?
Protected mode is a safety default (since Redis 3.2) that refuses connections from non-loopback clients when Redis is exposed with no password and no explicit bind configured; it exists to stop accidentally open instances from being hijacked.
When it triggers:
Enabled and no bind directive set and no requirepass/ACL password: only connections from 127.0.0.1 are accepted.
Remote clients get an error explaining how to secure the server.
Why it exists:
Redis has no auth by default; countless instances were left open on the public internet and abused (data theft, crypto miners).
It's a fail-safe so an unconfigured server isn't reachable from the outside.
How to open it up safely: Set a password/ACL and an explicit bind address rather than just disabling protected-mode no.
Q56.How can you secure Redis by renaming or disabling dangerous commands like FLUSHALL or CONFIG?
FLUSHALL or CONFIG?Redis lets you rename or fully disable individual commands via the rename-command directive in redis.conf, so destructive or dangerous operations either become unguessable or unavailable to clients.
Disable a command entirely: Rename it to an empty string: rename-command FLUSHALL "" makes the command nonexistent for all clients.
Rename to a secret name: e.g. rename-command CONFIG b9f2c7e1-admin: only operators who know the alias can call it, blocking casual/malicious use.
Common targets:
Data-wiping: FLUSHALL, FLUSHDB.
Reconfiguration/introspection: CONFIG, DEBUG, SHUTDOWN, KEYS (blocking on large datasets).
Caveats:
Renaming a command can break tools/clients that depend on it (e.g. Sentinel needs CONFIG).
This is defense-in-depth, not a substitute for network isolation, requirepass/ACLs, and binding to trusted interfaces.
Modern alternative: Redis 6+ ACLs (ACL SETUSER) let you grant/deny commands per user, which is more granular than renaming.
Q57.How does Redis manage client connections, and what does the maxclients setting control?
maxclients setting control?Redis is single-threaded for command execution but uses an event loop to multiplex many client sockets; maxclients caps how many simultaneous client connections the server will accept.
Connection handling model:
An I/O multiplexing event loop (epoll/kqueue) watches all client file descriptors and processes ready ones.
Commands run one at a time in the main thread, so each connection is cheap but shares CPU.
What maxclients controls:
The maximum number of concurrent connections (default 10000).
When exceeded, Redis rejects new connections with an error like max number of clients reached.
Tied to OS file descriptor limits: Redis reserves some FDs for itself; effective maxclients may be lowered if the ulimit is too low.
Practical guidance:
Use connection pooling on clients so you don't exhaust the limit with idle connections.
Inspect live connections with CLIENT LIST and set idle timeouts via timeout.
Q58.What is the primary difference between Redis Sentinel and Redis Cluster? When is Sentinel sufficient, and when must you move to Cluster?
Sentinel provides high availability (automatic failover) for a single-master dataset that fits on one node, while Cluster adds horizontal scaling by sharding data across many masters. The core difference: Sentinel keeps one dataset available; Cluster splits the dataset across nodes.
Redis Sentinel:
Monitors a master + replicas, promotes a replica if the master fails, and notifies clients of the new master.
All data lives on one master: no sharding, so capacity is bounded by one node's RAM.
Redis Cluster:
Partitions keys across multiple masters via hash slots, each master having its own replicas.
Provides both scaling and HA, but adds constraints (multi-key ops limited to one slot).
When Sentinel is sufficient:
Dataset fits comfortably in one server's memory and write throughput is served by a single master.
You want HA without the complexity of sharding.
When you must move to Cluster:
Data no longer fits on one node, or a single master can't handle the write load.
You need to scale horizontally while retaining automatic failover.
Q59.How does Redis Cluster decide which node stores a specific key? Explain the concept of 'Hash Slots' and why there are exactly 16,384 of them.
Redis Cluster maps every key to one of 16,384 hash slots, and each master owns a contiguous range of slots; the slot for a key is computed with CRC16(key) mod 16384.
How a key finds its node:
Compute CRC16(key) mod 16384 to get the slot number.
Look up which master currently owns that slot; the key lives there.
Hash tags: If a key contains {...}, only the substring inside braces is hashed, so {user1}:profile and {user1}:cart share a slot and can be used together in multi-key ops.
Why exactly 16,384:
Slots are a level of indirection: moving data means reassigning slots, not rehashing every key, so resharding is smooth.
Nodes gossip their slot ownership as a bitmap; 16384 bits = 2 KB, small enough to exchange cheaply in heartbeat messages.
It comfortably exceeds any realistic cluster size (Redis targets up to ~1000 nodes), giving fine-grained, balanced distribution.
Q60.How do you scale reads in Redis using replicas, and what are the consistency implications of reading from a replica?
You scale reads by attaching replicas to a master and routing read-only queries to them, but because Redis replication is asynchronous, replica reads are eventually consistent and can return stale data.
How to route reads to replicas:
In a cluster, the client issues READONLY on a replica connection so it serves reads for its master's slots instead of redirecting.
Add more replicas per master to increase read throughput horizontally.
Consistency implications:
Replication is asynchronous: a master acks the write before replicas apply it, so replicas may lag.
A read-after-write on a replica may not see the just-written value.
During failover, unreplicated writes on the old master can be lost entirely.
Mitigations:
Use WAIT to block until N replicas acknowledge a write when you need stronger guarantees.
Route reads that must be fresh to the master; send only staleness-tolerant reads to replicas.
Q61.What is Redis Stack, and what conceptual capabilities do modules like RediSearch or RedisJSON add compared to 'vanilla' Redis?
RediSearch or RedisJSON add compared to 'vanilla' Redis?Redis Stack is a distribution that bundles core Redis with a curated set of official modules plus tooling (RedisInsight), turning the key-value store into a multi-model data platform. Modules extend Redis with new data types and commands loaded into the server, so they run in-process at Redis speed.
What Redis Stack includes: Core Redis plus RediSearch, RedisJSON, RedisTimeSeries, and RedisBloom (probabilistic types).
RediSearch capabilities:
Adds secondary indexing and full-text search over hashes and JSON, so you can query by field values, not just by key.
Supports filtering, aggregation, and vector similarity search for embeddings (semantic search / RAG).
Without it, vanilla Redis has no query engine: you must design keys and index structures yourself.
RedisJSON capabilities:
Adds a native JSON type with atomic path-based updates via JSONPath (e.g. update one nested field).
Vanilla Redis would force you to store JSON as an opaque string and rewrite it wholesale on every change.
Why in-process modules matter: They avoid a separate search or document database, keeping data and query engine co-located in memory.
Q62.What is the impact of the 2024 Redis license change on the ecosystem (e.g., the rise of Valkey)?
In March 2024 Redis Inc. relicensed Redis away from the permissive BSD license to dual source-available licenses (RSALv2 and SSPLv1), which are not OSI-approved open source. This mainly targets cloud providers reselling Redis as a managed service, and it triggered a community fork, Valkey, backed by the Linux Foundation and major cloud vendors.
What actually changed:
Redis 7.4+ ships under source-available terms; you can read and modify the code but face restrictions on offering it as a competing managed service.
The last truly open-source (BSD) version was Redis 7.2.4.
The rise of Valkey:
Valkey is a BSD-licensed fork from Redis 7.2.4, hosted by the Linux Foundation and supported by AWS, Google Cloud, Oracle, and others.
It aims to stay a drop-in, wire-compatible replacement, so existing clients and tooling keep working.
Other forks exist too (e.g. Redict), but Valkey gained the most momentum.
Ecosystem impact:
Cloud providers began offering Valkey-based services to avoid the new terms.
Teams now must decide: stay on Redis (features, modules) or move to Valkey (permissive license, community governance).
Postscript: Redis added back an AGPLv3 open-source option in Redis 8 (2025) in response to the backlash.
Q63.What is Redis Stack, and when would you use RedisJSON over a standard Redis Hash?
RedisJSON over a standard Redis Hash?Redis Stack bundles Redis with official modules (RediSearch, RedisJSON, RedisTimeSeries, RedisBloom) to make it multi-model. Choose RedisJSON over a plain Hash when your data is deeply nested or has arrays and you need atomic updates to individual sub-elements; a Hash is best for a flat, single-level set of fields.
Redis Hash characteristics:
A flat map of field to string value: no nesting, no native arrays or numeric-typed values.
Very memory-efficient and simple for shallow objects (a user with name, email, age).
RedisJSON characteristics:
Stores a full JSON document with nested objects, arrays, numbers, and booleans.
Supports path operations: read or update a nested field with JSON.SET key $.address.city without rewriting the whole document.
Integrates with RediSearch so you can index and query JSON fields.
When to pick which:
Use a Hash for flat records and maximum memory efficiency.
Use RedisJSON for nested/hierarchical data, array manipulation, or partial atomic updates to sub-fields.
With a Hash, nesting forces you to flatten keys or serialize JSON into one string (losing atomic partial updates).
Q64.What are the geospatial commands in Redis (GEOADD, GEOSEARCH), and how does Redis store and query location data internally?
GEOADD, GEOSEARCH), and how does Redis store and query location data internally?Redis geospatial commands let you store latitude/longitude points and query them by proximity. Internally there is no special geo type: Redis encodes each coordinate pair as a single 52-bit Geohash integer and stores it as the score in a sorted set, so all the usual sorted-set machinery powers geo queries.
Key commands:
GEOADD: add a member with its longitude and latitude.
GEOSEARCH: find members within a radius or a rectangular box of a point or another member, optionally sorted by distance.
GEODIST, GEOPOS, GEOHASH: distance between members, decode coordinates, and get the geohash string.
How it is stored internally:
The 2D coordinate is interleaved (bit-interleaving) into a 1D 52-bit Geohash number.
That number is the score in a ZSET; nearby locations produce numerically close scores.
How queries work:
A radius search computes the geohash ranges covering the search area, does sorted-set range scans over those buckets, then filters candidates by exact distance.
Because it is a plain sorted set, you can inspect or delete members with normal ZSET commands (e.g. ZREM).
Q65.What conceptual capabilities do RedisBloom and RedisTimeSeries add to Redis?
RedisBloom and RedisTimeSeries add to Redis?RedisBloom and RedisTimeSeries are Redis Stack modules that add specialized data types Redis core lacks: RedisBloom provides probabilistic structures that answer set/frequency questions with tiny memory, and RedisTimeSeries provides an efficient store for timestamped metric data with built-in aggregation.
RedisBloom (probabilistic data structures):
Bloom and Cuckoo filters: fast approximate membership tests ("have I seen this item?") with no false negatives but tunable false positives, using far less memory than a set.
Count-Min Sketch: approximate frequency counts for heavy-hitter detection.
Top-K: track the most frequent items in a stream.
t-digest: approximate quantiles/percentiles over a distribution.
Trade-off: you accept bounded error in exchange for constant, small memory: ideal for dedup, rate-limiting checks, and analytics at scale.
RedisTimeSeries:
A native time-series type: append timestamped samples with TS.ADD and query ranges with TS.RANGE.
Downsampling via compaction rules that automatically roll raw samples into aggregates (avg, min, max, sum) over buckets.
Labels on each series enable filtering and multi-series queries, plus retention policies to auto-expire old data.
Replaces hand-rolling metrics in sorted sets, which is memory-heavy and lacks aggregation.
Q66.Redis 6.0 introduced multi-threading. Does this mean the core execution is now multi-threaded? If not, what exactly do those extra threads do?
No. Redis 6.0's multi-threading only parallelizes network I/O (reading requests from sockets and writing replies); command execution, and thus the manipulation of the keyspace, remains single-threaded.
Core execution stays single-threaded: All commands still run one at a time on the main thread, preserving the atomicity and lock-free simplicity Redis is known for.
I/O threads handle socket work:
They parallelize the syscalls of reading the request buffer and writing the response, which is where a busy server spends much of its time.
Parsing and executing the actual command still happens on the single main thread.
Why it was added: On high-throughput workloads with many clients, network I/O became the bottleneck before CPU-bound command execution did.
Configured explicitly: Enable with io-threads (and io-threads-do-reads); it's off by default and only worthwhile at high load.
Note: background threads for tasks like UNLINK, async FLUSHDB, and fsync existed before 6.0 (lazyfree); those are separate from the new I/O threads.
Q67.Explain the internal encoding of a List (ziplist/listpack). Why does Redis change the internal representation based on size?
List (ziplist/listpack). Why does Redis change the internal representation based on size?A List is stored as a compact sequential structure (listpack, the successor to ziplist) wrapped in a quicklist; Redis switches encodings by size to trade CPU for memory, keeping small lists tiny and large lists fast to modify.
listpack / ziplist:
A single contiguous, serialized blob of entries: very memory-dense, cache-friendly.
Downside: inserts/deletes may require shifting or reallocating the whole block, and lookups are O(N), fine only while it is small.
quicklist: A doubly linked list of listpack nodes; combines low overhead per node with cheap push/pop at both ends.
Why switch on size:
Small collections: the compact form saves memory and pointer overhead, and O(N) is negligible for a handful of items.
Large collections: the flat blob becomes expensive to mutate, so Redis breaks it into linked nodes for better time complexity.
Thresholds are tunable via list-max-listpack-size (entries per node) and value size limits.
Q68.How do Redis Hashes handle memory optimization internally (e.g., ziplists vs. hashtables)?
Hashes handle memory optimization internally (e.g., ziplists vs. hashtables)?Redis stores small Hashes as a compact listpack (formerly ziplist) and automatically converts to a real hash table once the Hash grows past configured limits, trading a little CPU for large memory savings on small objects.
listpack / ziplist (small Hashes):
Field/value pairs stored sequentially in one contiguous block: minimal pointer and allocation overhead.
Lookups are O(N) linear scans, acceptable because the Hash is small.
hashtable (large Hashes): A true hash table gives O(1) field access but costs more memory per entry (pointers, buckets).
Conversion thresholds:
Controlled by hash-max-listpack-entries (field count) and hash-max-listpack-value (value size).
Exceeding either permanently promotes the Hash to a hashtable (it does not shrink back).
Practical takeaway: Many small Hashes are very memory-cheap, which is why sharding large data into small Hashes is a common optimization.
Q69.How are expired keys handled on replicas versus the master in Redis?
The master is authoritative about expiration: only it actively deletes expired keys and propagates a DEL (or UNLINK) to replicas. A replica never expires keys on its own, so the master stays the single source of truth.
Master side:
Uses lazy expiration (on access) plus active expiration (periodic sampling of keys with TTLs).
When it expires a key, it sends an explicit delete command to all replicas and the AOF.
Replica side:
Does not independently delete expired keys; it waits for the master's DEL.
For reads, a logically expired key is treated as absent (returns nil) even though it still occupies memory until the master's delete arrives.
Why this design: Prevents replicas from diverging from the master and avoids inconsistent reads across the topology.
Q70.What is the 'Copy-on-Write' (CoW) mechanism, and how does Redis use it during persistence?
Copy-on-Write is an OS memory optimization where a forked child process initially shares the same physical memory pages as the parent; a page is only physically copied when one of them writes to it. Redis relies on this so it can persist a consistent snapshot without blocking or duplicating all memory.
The fork: During BGSAVE or AOF rewrite, Redis calls fork(); the child gets a virtual copy of the dataset frozen at that instant.
Shared pages: Parent and child point to the same physical pages, marked read-only, so no data is copied upfront.
Copy on write: When the parent (still serving writes) modifies a key, the OS copies just that page, leaving the child's snapshot untouched.
Why Redis uses it: The main process keeps serving clients while the child writes a consistent snapshot to disk.
The catch: Under heavy write load, many pages get copied, so memory usage can spike toward 2x during persistence.
Q71.Explain how Redis replication works. What is the difference between a 'Full Resync' and a 'Partial Resync' (PSYNC)?
PSYNC)?Redis replication is asynchronous: a replica connects to a master, gets an initial copy of the dataset, then streams the master's ongoing write commands. PSYNC lets a reconnecting replica avoid a costly full copy when possible: a full resync ships the whole dataset, while a partial resync only replays the missed commands from a buffer.
Initial sync flow: Replica sends PSYNC; master decides full or partial based on the replication ID and offset.
Full Resync:
Master forks and produces an RDB snapshot, sends it to the replica, then streams buffered new writes.
Expensive: happens on first connect or when partial isn't possible.
Partial Resync (PSYNC):
On a brief disconnect, the replica asks to resume from its last offset.
If the requested offset still exists in the master's repl-backlog (a circular buffer) and replication IDs match, the master resends only the missing command stream.
Key mechanisms:
Replication ID identifies the data history; offset tracks position in the stream.
A large enough repl-backlog-size makes partial resyncs succeed across longer network blips.
Q72.How does Redis 7's 'Multi-part AOF' improve upon the traditional AOF mechanism?
AOF mechanism?Redis 7 replaced the single monolithic AOF file with a multi-part design: a base file (an RDB or AOF snapshot) plus one or more incremental files, all tracked by a manifest. This makes rewrites cheaper, safer, and faster to load compared to the traditional single-file AOF.
Old single-file problem: A rewrite had to build a whole new AOF and buffer live writes in memory, then merge them, using extra memory and I/O.
Multi-part structure:
Base file: a compact snapshot of the dataset (RDB-format by default).
Incremental file(s): commands appended since the last base.
Manifest file: lists which files form the current AOF.
Benefits:
Rewrites no longer buffer new writes in memory then rewrite them: less memory pressure and I/O.
Faster recovery since loading starts from a compact base and replays only the increment.
Simpler, more robust handling: files live in an appenddirname directory managed via the manifest.
Q73.What is an AOF rewrite, and why is it necessary? How does Redis 7's 'Multi-Part AOF' improve this process?
AOF rewrite, and why is it necessary? How does Redis 7's 'Multi-Part AOF' improve this process?An AOF rewrite compacts the append-only log by regenerating a minimal set of commands that reproduce the current dataset, discarding redundant history (e.g. many updates to one key collapse into its final value). It is necessary because the AOF grows unbounded as writes accumulate. Redis 7's Multi-Part AOF makes rewriting much cheaper by writing a fresh base snapshot instead of rewriting one giant file in place.
Why rewrite is needed: Without it the AOF keeps every historical write (100 INCRs instead of one final value), bloating disk and slowing recovery.
How rewrite works (traditional):
Triggered by BGREWRITEAOF or auto thresholds (auto-aof-rewrite-percentage).
Child process writes a minimal AOF; new writes during the rewrite were buffered and appended afterward.
Multi-Part AOF improvement:
Rewrite just produces a new compact base file plus a fresh incremental file, tracked by a manifest.
No in-memory rewrite buffer to merge back: lower memory and CPU cost.
Reduced risk of corruption and faster loading since the base is a snapshot rather than replayed commands.
Q74.How does Redis perform a background save (BGSAVE) without blocking the main thread — explain the role of fork() and Copy-on-Write?
BGSAVE) without blocking the main thread — explain the role of fork() and Copy-on-Write?On BGSAVE, Redis calls fork() to create a child process that owns a consistent point-in-time view of memory. The child writes the RDB to disk while the parent keeps serving clients, and the OS uses Copy-on-Write so the two processes share physical memory until pages are modified.
fork() creates a child process: The child inherits a snapshot of the dataset as it was at fork time and serializes it to disk.
Copy-on-Write avoids duplicating memory:
Parent and child share the same physical pages initially; forking doesn't copy all data.
When the parent modifies a key, the OS copies just that page, so the child still sees the original.
Main thread stays responsive: Only the brief fork() itself pauses the parent; disk I/O happens entirely in the child.
The cost: memory and fork latency: Heavy writes during save cause many page copies, spiking memory; a large dataset makes fork() slower (copying page tables).
Q75.If Redis crashes, how does it ensure data consistency upon restart if both RDB and AOF are enabled?
RDB and AOF are enabled?When both are enabled, Redis prefers the AOF on restart because it is more complete (more recent) than the periodic RDB snapshot. With hybrid persistence, that AOF file itself already contains an RDB preamble plus the recent command tail, giving both speed and completeness.
AOF wins by default: Controlled by aof-use-rdb-preamble and the fact that AOF captures writes more frequently than RDB snapshots.
Loading order: If AOF is enabled, Redis loads it and ignores the standalone RDB; if AOF is disabled, it falls back to the RDB.
Consistency guarantee: AOF replays a log of write operations, reconstructing state up to the last fsync'd command, so you lose at most the un-synced tail.
Corruption safety net: A truncated AOF (from a crash mid-write) can be repaired with redis-check-aof --fix.
Q76.Is Redis a 'durable' database? Explain how the appendfsync policy (always, everysec, no) affects the risk of data loss during a crash.
appendfsync policy (always, everysec, no) affects the risk of data loss during a crash.Redis can be durable, but durability is tunable, not absolute: the appendfsync setting decides how often the AOF buffer is flushed to disk with fsync, trading throughput against how much data you can lose in a crash.
appendfsync always: fsync on every write: strongest durability (near-zero loss) but slowest.
appendfsync everysec (default): Flushes once per second: on crash you lose at most ~1 second of writes, with good performance. The practical sweet spot.
appendfsync no: Redis never calls fsync itself; the OS flushes on its own schedule (often ~30s), so a crash can lose much more, but fastest.
Caveat: Even always isn't a distributed guarantee: acknowledged writes can be lost on failover in a replicated setup.
Q77.If you need 'zero data loss' in Redis, how would you configure your persistence and sync settings?
True zero data loss is impossible to guarantee absolutely, but you get closest by enabling AOF with appendfsync always, combined with synchronous replication and quorum acknowledgment to survive node failures.
Enable AOF with per-write fsync: appendonly yes and appendfsync always so every command hits disk before the client is told success.
Require replica acknowledgment: Use WAIT numreplicas timeout so writes are confirmed on replicas before returning, surviving a primary crash.
Reject unsafe writes: Set min-replicas-to-write so the primary stops accepting writes if too few replicas are connected.
Understand the tradeoff: This is the slowest configuration; asynchronous replication and failover still leave a small window, so "zero loss" is a best-effort target.
Q78.What is the performance impact of the appendfsync always policy in AOF?
appendfsync always policy in AOF?With appendfsync always, Redis issues an fsync to disk on effectively every write command, so throughput and latency become bound by disk speed rather than memory speed. This can cut write throughput dramatically compared to everysec.
Every write waits for disk: An fsync is a slow, blocking system call; forcing it per command adds latency to each write.
Throughput collapse on slow disks: On spinning disks it can drop from hundreds of thousands to a few thousand writes/sec; even on SSDs it's a large hit.
Single-threaded amplification: Because the main thread drives command processing, disk stalls translate directly into request latency for all clients.
Why everysec is usually chosen: Batching one fsync per second gives near-full performance while capping loss at about a second.
Q79.What is diskless replication in Redis, and when is it beneficial?
Q80.Explain the 'Big Key' problem — how do you identify big keys, and why are they dangerous in a single-threaded system?
Q81.What is the 'Hot Key' problem in a Redis Cluster, and how can you mitigate it?
Q82.How do you prevent a "Cache Stampede" (Thundering Herd) using Redis?
Q83.What are common causes of latency spikes in Redis, and how would you troubleshoot them?
Q84.Are Redis transactions (MULTI/EXEC) ACID compliant? Why is there no 'rollback' mechanism if a command fails mid-transaction?
MULTI/EXEC) ACID compliant? Why is there no 'rollback' mechanism if a command fails mid-transaction?Q85.What does the WAIT command do, and how does it help achieve stronger consistency guarantees in Redis?
WAIT command do, and how does it help achieve stronger consistency guarantees in Redis?Q86.How does Redis approximate the LRU (Least Recently Used) algorithm?
Q87.How does Redis approximate LFU eviction, and how does it track access frequency over time?
Q88.How do 'Consumer Groups' work in Redis Streams, and how do they differ from Kafka consumer groups?
Q89.What is the Pending Entries List (PEL) in a Redis Stream consumer group, and how do XACK and XCLAIM manage message reprocessing?
XACK and XCLAIM manage message reprocessing?Q90.What is a Sorted Set (ZSET), and how does it implement a sliding window rate limiter?
ZSET), and how does it implement a sliding window rate limiter?Q91.In a Redis Cluster, what is the difference between a MOVED error and an ASK error, and how should a smart client handle them?
MOVED error and an ASK error, and how should a smart client handle them?Q92.How does Redis handle a 'split-brain' scenario in a Sentinel-managed setup?
Q93.How does Redis Sentinel achieve a quorum for failover?
Q94.Why does Redis Cluster use asynchronous replication, and what are the implications for data consistency during a failover?
Q95.What is a hash tag in Redis Cluster, and how does it enable multi-key operations on the same node?
Q96.How do multi-key commands (like MGET or SUNION) behave in a Redis Cluster, and what are the constraints?
MGET or SUNION) behave in a Redis Cluster, and what are the constraints?Q97.How does Redis Cluster propagate node state and detect failures? Explain the gossip protocol.
Q98.How does resharding work in a Redis Cluster when you add or remove a node?
Q99.How does Redis Sentinel discover replicas and propagate the new configuration after a failover?
Q100.How would you implement a basic distributed lock using SETNX? What are the potential pitfalls, and how does the Redlock algorithm attempt to solve them?
SETNX? What are the potential pitfalls, and how does the Redlock algorithm attempt to solve them?Q101.What is the Redlock algorithm, and why is it controversial in the distributed systems community?
Q102.What is fencing in the context of distributed locks, and why do fencing tokens matter for lock safety?
Q103.Explain 'Server-Assisted Client-Side Caching' introduced in Redis 6. How does the server notify the client that its local cache is stale?
Q104.What is the RESP (Redis Serialization Protocol), and what is the difference between RESP2 and RESP3, specifically regarding push notifications and client-side caching?
RESP (Redis Serialization Protocol), and what is the difference between RESP2 and RESP3, specifically regarding push notifications and client-side caching?