Database / REDIS
1. What is a Redis key?
A key is the unique string identifier used to store and retrieve a value in Redis — every piece of data in Redis, regardless of its type (string, hash, list, set, and so on), is addressed by exactly one key, the same way a variable name addresses a value in a program.
SET user:1001:name "Alex" GET user:1001:name
Keys are binary-safe strings, so they can technically contain any bytes, but in practice teams adopt a consistent naming convention — commonly colon-separated segments like user:1001:name — to keep related keys organized and scannable. Redis has no built-in concept of "folders" or namespaces beyond this naming convention, so key design is entirely up to the application, and a poorly thought-out key scheme is a common source of operational pain as a dataset grows.
2. What is Redis?
Redis is an open source in-memory data structure store which can be used as a database and/or a cache and message broker.
NoSQL Key/Value Store.
Supports Multiple data structures.
Built in Replication.
3. What is the purpose of the EXPIRE command?
EXPIRE attaches a time-to-live to an existing key, after which Redis automatically removes it — useful for data that should only be valid temporarily, like a session token, a rate-limit counter, or a cached query result that shouldn't be served stale forever.
SET session:abc123 "user-data" EXPIRE session:abc123 3600 # expires in 3600 seconds (1 hour) TTL session:abc123 # check remaining time-to-live
Related commands round out TTL management: PEXPIRE sets the TTL in milliseconds for finer granularity, EXPIREAT/PEXPIREAT set an absolute expiration timestamp instead of a relative duration, and PERSIST removes a key's TTL entirely, making it permanent again. A key's TTL is also cleared if the key is overwritten with a plain SET (unless the KEEPTTL option is used), which is a common source of confusion when a value update unexpectedly makes a previously-expiring key permanent.
4. List few Redis Datatypes.
Redis supports,
- Strings,
- Lists,
- Sets,
- Sorted Sets,
- Hashes,
- Bitmaps,
- Hyperlogs,
- and Geospatial indexes.
5. Advantages of Redis.
- Very Flexible.
- No Schema and column names.
- Very fast, can perform around 110K Set per second and 81K GETS per second.
- Rich Datatype support,
- command level Atomic Operation,
- Caching & Disk Persistence.
6. What is a Redis Sorted Set?
A Sorted Set (ZSET) stores unique members the same way a plain Set does, but pairs each member with a floating-point score, and Redis automatically keeps the whole collection ordered by that score — giving you a structure that's simultaneously a unique-membership set and an ordered ranking, without needing to re-sort anything yourself.
ZADD leaderboard 1500 "alex" ZADD leaderboard 2200 "sam" ZRANGE leaderboard 0 -1 WITHSCORES # returns members in ascending score order ZRANK leaderboard "alex" # returns alex's rank (0-indexed)
Because Redis maintains this order internally using a skip list plus a hash table, range queries by score or by rank (ZRANGE, ZRANGEBYSCORE) and rank lookups (ZRANK) are efficient even on large sets, which is exactly what makes Sorted Sets the natural fit for leaderboards, priority queues, and time-ordered event feeds where the score is often a timestamp.
7. What is a Redis Hash used for?
A Hash stores a set of field-value pairs under a single key, similar to a small object or a row in a table — instead of serializing an entire object into one string value, a Hash lets you store and update individual fields of that object directly.
HSET user:1001 name "Alex" age "30" email "alex@example.com" HGET user:1001 name HGETALL user:1001 HINCRBY user:1001 age 1
The practical benefit over storing a JSON-encoded string is field-level access: updating just the age field via HSET or HINCRBY doesn't require reading, deserializing, modifying, and rewriting the entire object, which matters both for network efficiency and for avoiding lost updates if multiple clients touch different fields of the same record concurrently. Hashes are commonly used to represent an entity like a user profile, a product, or a configuration set, where individual attributes are read or updated independently of each other.
8. What programming languages does Redis support?
REDIS supports most of the programming languages including Java, C#, Python, Scala, C++, R, PHP and many more.
9. Explain Replication in Redis.
Redis supports simple master to slave replication. When a relationship is established, data from the master is replicated to the slave.
10. What is a Redis Set data type used for?
A Set stores an unordered collection of unique strings — no duplicates are allowed, and there's no concept of order or position the way a List has. Its core value is fast membership testing and set algebra: checking whether an item exists, and combining multiple sets via union, intersection, or difference.
SADD tags:post123 "redis" "database" "nosql" SISMEMBER tags:post123 "redis" # membership check, O(1) SINTER tags:post123 tags:post456 # intersection of two sets SCARD tags:post123 # count of members
Typical use cases include tagging (a post's set of tags), tracking unique visitors or unique events (adding a user ID to a set naturally de-duplicates), and relationship queries like "users who like both A and B" via SINTER. Because membership checks and set operations run in close to constant or linear time relative to set size rather than requiring a full scan, Sets are a common choice whenever the core question is "is X in this collection" or "what do these two collections have in common."
11. Explain about REDIS security.
Redis is designed to be accessed by trusted clients.
REDIS can be restricted to certain interfaces.
Data encryption not supported and hence do not allow external access/internet exposure.
12. What is the purpose of the INCR command?
INCR atomically increments the integer value stored at a key by 1, returning the new value — and because it's atomic, it's safe to call concurrently from many clients without a race condition, unlike a naive "read the current value, add 1, write it back" sequence performed in application code.
SET pageviews:home 0 INCR pageviews:home # 1 INCRBY pageviews:home 5 # 6 DECR pageviews:home # 5 INCRBYFLOAT price 2.50 # for floating-point increments
This atomicity is the entire point: two clients calling INCR on the same key at the same moment are guaranteed to each get a distinct, correctly-incremented result, with no lost updates — a property that would require explicit locking to replicate safely if the increment were instead implemented as separate GET and SET calls. This makes INCR the standard building block for counters, rate limiters, and unique ID generation in Redis-backed applications.
13. What is a Redis Stream?
A Stream is an append-only log data structure, similar in spirit to a Kafka topic, where each entry gets a unique, time-ordered ID and holds a set of field-value pairs. Unlike Pub/Sub, entries persist in the stream and can be read by multiple independent readers at their own pace, including readers that connect after an entry was added.
XADD events * sensor "temp-1" reading "72.5" XRANGE events - + # read all entries XLEN events # entry count
Each entry ID (like 1691425200000-0) encodes a millisecond timestamp plus a sequence number, which is what gives Streams their strict, gap-free ordering. Streams support both simple sequential reading and, through consumer groups, coordinated parallel processing across multiple readers — making them Redis's answer to durable, replayable event log use cases that a Set, List, or Pub/Sub channel isn't designed to handle well on its own.
14. Expand REDIS.
Redis stands for REmote DIctionary Server.
15. Define a Redis Bitmap?
A Bitmap isn't a separate data type in Redis — it's a way of treating an ordinary String value as a compact array of individual bits, addressed by offset, using dedicated bit-level commands. Because a String can hold up to 512MB, a single key can represent billions of individual boolean flags extremely compactly.
SETBIT user:1001:active_days 5 1 # mark day 5 as active GETBIT user:1001:active_days 5 # check day 5 BITCOUNT user:1001:active_days # count how many bits are set
The classic use case is tracking a large number of boolean states per entity extremely cheaply — whether a user was active on each day of the year (365 bits = under 46 bytes), feature-flag membership across millions of users, or approximate presence tracking. BITCOUNT and bitwise operations like BITOP AND/OR let you answer questions like "how many users were active on both day 5 and day 6" across huge populations using a handful of fast, memory-efficient operations rather than scanning individual records.
16. In which language Redis is developed?
Redis is developed using ANSI C and mostly used for cache solution and session management. It creates unique keys for store values.
17. What is the purpose of Redis Pub/Sub?
Pub/Sub lets clients broadcast messages on named channels to any number of subscribers listening at that moment, without Redis storing the message anywhere — it's a pure, ephemeral fire-and-forget messaging mechanism, not a durable queue.
# subscriber SUBSCRIBE notifications # publisher, from a different client PUBLISH notifications "New order received"
If no client is subscribed to a channel when a message is published, that message is simply lost — there's no backlog a late-joining subscriber can catch up on, which is the key difference from a Redis Stream. This makes Pub/Sub well suited to real-time notifications where only currently-connected clients need to know (like pushing a live update to open browser tabs), and poorly suited to anything where a message must be reliably delivered even to a consumer that wasn't listening at the exact moment it was sent.
18. Difference between SET and MSET command in REDIS.
SET command creates one key-value pair while using MSET command, multiple key-value pairs can be created.
19. Explain LPUSH command in REDIS.
LPUSH inserts all the specified values at the head of the list stored at key. If the key does not exist, it is created as an empty list before performing the push operations. When key holds a value that is not a list, an error is returned.
Usage: LPUSH key value [value ...]
redis> LPUSH mylist "World" (integer) 1 redis> LPUSH mylist "Hello" (integer) 2 redis> LRANGE mylist 0 -1 1) "Hello" 2) "World" redis>
20. What are Redis transactions?
A Redis transaction bundles multiple commands so they execute as a single, uninterrupted sequence — no other client's commands can be interleaved in the middle of a transaction once it starts executing, which is what gives Redis transactions their isolation guarantee.
MULTI SET account:1:balance 100 DECRBY account:1:balance 20 INCRBY account:2:balance 20 EXEC
MULTI begins queuing subsequent commands rather than executing them immediately; EXEC runs the entire queued batch atomically, back to back; DISCARD cancels a queued transaction before it runs. Redis transactions differ from typical relational-database transactions in one important way: there's no mid-transaction rollback for a command that fails at runtime (like a type error) — the rest of the queued commands still execute, and only commands with syntax errors caught at queue time prevent EXEC from running at all. WATCH adds optimistic locking on top, aborting the transaction if a watched key changes before EXEC, which is the standard pattern for implementing check-then-act logic safely.
21. Limitations of REDIS.
REDIS is single threaded.
It has got limited client support for consistent hashing.
It has significant overhead for persistence.
It cannot be deployed widely.
22. What is RDB persistence in Redis?
RDB (Redis Database) persistence works by taking a point-in-time snapshot of the entire in-memory dataset and writing it to a single compact binary file on disk, either on a configured schedule or on demand. Because it's a full snapshot rather than a running log, restarting from an RDB file is fast — Redis just loads one file back into memory.
# redis.conf save 900 1 # snapshot if at least 1 key changed in 900 seconds save 300 10 # snapshot if at least 10 keys changed in 300 seconds
BGSAVE # trigger a snapshot in the background, non-blocking
The trade-off is the gap between snapshots: any writes that happened after the last successful snapshot are lost if Redis crashes before the next one completes, so RDB alone offers weaker durability than a continuously-appended log. BGSAVE forks a child process to write the snapshot so the main Redis process keeps serving requests during the save, but that fork itself briefly duplicates memory pages (via copy-on-write), which is a real operational consideration on memory-constrained instances with very large datasets.
23. REDIS is fast, but is it also durable?
No. Redis compromises with durability to enhance the speed. In Redis, in the case of system failure or crash, it writes to disk but may fall behind and lose the data which is not stored.
24. What is AOF persistence in Redis?
AOF (Append Only File) persistence logs every write operation to a file as it happens, in the order it was executed, rather than periodically snapshotting the whole dataset. Recovering from an AOF file means replaying that log of commands from the start to rebuild the exact dataset state.
# redis.conf appendonly yes appendfsync everysec # fsync to disk roughly once per second
The appendfsync setting controls the durability/performance trade-off directly: always fsyncs after every write (safest, slowest), everysec fsyncs about once per second (a common middle-ground default, risking at most ~1 second of writes on a crash), and no lets the OS decide when to flush (fastest, least durable). Because a command-by-command log would grow indefinitely otherwise, Redis periodically performs AOF rewriting, compacting the log into the minimal set of commands needed to reproduce the current dataset, which keeps the file from growing unbounded while preserving the stronger durability AOF offers over RDB snapshots alone.
25. What is the purpose of the SELECT command in Redis?
Redis supports multiple numbered logical databases within a single server instance (16 by default, indexed 0-15), and SELECT switches the current connection's active database to a given index, scoping subsequent commands to just that database's keyspace.
SELECT 1 SET debug:flag "on" # stored in database 1, not database 0 SELECT 0 GET debug:flag # returns nil; that key lives in database 1
It's a lightweight way to logically separate data within one Redis instance — for example, keeping a test dataset in database 1 while production data stays in database 0 — without running multiple Redis processes. It's worth knowing the real limitations, though: numbered databases share the same memory pool and the same persistence configuration, offer no per-database access control on their own, and are explicitly unsupported in Redis Cluster mode, which only exposes database 0. For genuine multi-tenant isolation with independent resource limits or access control, separate Redis instances or key-prefixing conventions are generally the better-supported approach.
26. Difference between Memcached and REDIS.
| Memcached. | REDIS. |
| Memcached is multi-threaded. | Redis is single threaded. |
| Memcached only does caching information. | Redis does caching information and also supports persistence and replication. |
| Memcached supports the functionality of LRU (Least Recently Used) eviction of values. | Redis does not support the functionality of LRU eviction of values. |
| In Memcached when they overflow memory, the one you have not used recently (LRU- Least Recently Used) will get deleted. | In Redis you can set a time out on everything, when memory is full, it will look at three random keys and deletes the one which is closest to expiry. |
| Memcached supports CAS(Check And Set). It is useful for maintaining cache consistency. | Redis does not support CAS ( Check And Set). |
27. What is the purpose of the TTL command?
TTL returns how many seconds remain before a key expires, letting an application check a key's remaining lifetime without having to track expiration times itself in separate application logic.
SET session:abc123 "data" EX 3600 TTL session:abc123 # returns remaining seconds, e.g. 3599 TTL nonexistent:key # returns -2, key doesn't exist TTL permanent:key # returns -1, key exists but has no TTL set
The two special return values are worth memorizing since they're a common source of subtle bugs: -2 means the key doesn't exist at all, while -1 means the key exists but has no expiration set — conflating these two (for example, treating any negative TTL as "expired") can cause an application to misdiagnose a permanent key as missing. PTTL returns the same information in milliseconds for finer-grained checks.
28. What is SADD command in REDIS?
Add the specified members to the set stored at key. Specified members that are already a member of this set are ignored. If key does not exist, a new set is created before adding the specified members.
An error is returned when the value stored at key is not a set.
Usage: SADD key member [member ...]
Example: redis> SADD myset "Hello" (integer) 1 redis> SADD myset "World" (integer) 1 redis> SADD myset "World" (integer) 0 redis> SMEMBERS myset 1) "World" 2) "Hello"
29. Define eviction policies in Redis?
When Redis is used as a cache with a fixed maxmemory limit, an eviction policy determines which keys get removed once that limit is reached and new writes still need room — without a policy that allows eviction, Redis would instead simply reject new writes with an out-of-memory error once the limit is hit.
| Policy | Behavior |
| noeviction | Reject writes once memory limit is reached; default setting. |
| allkeys-lru | Evict the least recently used key, across all keys. |
| allkeys-lfu | Evict the least frequently used key, across all keys. |
| volatile-lru | Evict least recently used, but only among keys with a TTL set. |
| volatile-ttl | Evict the key with the shortest remaining TTL first. |
| allkeys-random | Evict a random key, across all keys. |
The right choice depends on how Redis is being used: a pure cache where any key can reasonably be recomputed typically uses allkeys-lru or allkeys-lfu, while a mixed deployment storing some permanent data alongside expiring cache entries uses one of the volatile-* policies to ensure only the expiring, cache-like keys are ever candidates for eviction.
30. Mention few LIST operations in REDIS.
LPUSH adds an element to the beginning of a list.
RPUSH add an element to the end of a list.
LPOP removes the first element from a list and returns it.
RPOP removes the last element from a list and returns it.
LLEN gets the length of a list.
LRANGE gets a range of elements from a list.
31. Mention Spring Boot Drivers for REDIS.
Spring Boot primarily supports two main Redis drivers (clients): Lettuce (which is the default) and Jedis. It abstracts these clients using the Spring Data Redis framework, allowing developers to switch between them easily.
Supported Redis Drivers
Lettuce
This is the default Redis client used in Spring Boot applications when you include the spring-boot-starter-data-redis dependency.
- It is built on Netty and is an advanced, thread-safe Redis client.
- Its thread-safe nature means a single connection instance can be shared across multiple threads, which can lead to more efficient resource usage and fewer physical connections to the Redis server.
- Lettuce supports both synchronous and reactive (non-blocking) APIs, making it a good fit for modern, reactive Spring applications.
Jedis
This client is also fully supported by Spring Data Redis, although it requires explicitly excluding the default Lettuce dependency and including the Jedis one instead in your pom.xml or build.gradle file.
- It provides a straightforward, synchronous API that closely mirrors the original Redis commands.
- Unlike Lettuce, Jedis is generally not thread-safe for shared instances, so it relies on connection pooling in multi-threaded environments to manage connections effectively.
32. What is Redis Sentinel used for?
Sentinel is a separate, lightweight process (or set of processes) that monitors a Redis master and its replicas, and automatically handles failover if the master becomes unavailable — promoting a replica to master and reconfiguring the rest of the replicas to follow the new master, without a human needing to intervene.
# sentinel.conf sentinel monitor mymaster 127.0.0.1 6379 2 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 60000
Running multiple Sentinel instances (typically 3 or 5, spread across different hosts) is standard, since a single Sentinel would itself be a single point of failure for failover detection; Sentinels use a quorum vote among themselves to agree a master is genuinely down before triggering failover, which guards against one Sentinel mistakenly declaring a failure due to its own local network issue. Sentinel is aimed at high availability for a single logical dataset (one master, several replicas); for horizontally scaling data across multiple masters, Redis Cluster is the separate, complementary tool.
33. Explain about redisson client for redis.
Redisson is a popular, open-source Java client for Redis (and Valkey) that offers a simplified, thread-safe way for Java developers to interact with the Redis data store. It abstracts the complexities of the Redis API by providing familiar Java objects and data structures, such as Map, List, Queue, and Lock, as distributed objects.
Key Features and Benefits of Redisson
- Familiar Java Interfaces
- Redisson provides implementations of common Java collections and data structures, allowing developers to use Redis with a minimal learning curve.
- Distributed Objects and Services
- It extends Redis's capabilities with distributed implementations of services like locks, semaphores, and Remote Procedure Calls (RPC).
- Integration with Java Ecosystem
- Redisson offers seamless integration with various popular Java frameworks, including
Spring Cache,Spring Session,Hibernate Cache, andJCache API (JSR-107). - Asynchronous and Reactive APIs
- It supports synchronous, asynchronous, reactive streams, and
RxJavaAPIs, catering to different application needs and performance requirements. - High Performance Caching
- Redisson enhances caching performance with features like "near cache," which stores frequently accessed data on the Java heap for faster retrieval.
- Support for Various Redis Deployments
- It supports different Redis configurations, including standalone, master-slave, and cluster modes.
34. What is Redis Cluster?
Redis Cluster is Redis's built-in solution for horizontally scaling data across multiple nodes — instead of one server holding the entire dataset, the keyspace is split into 16,384 fixed hash slots, and those slots are distributed across the cluster's master nodes, each of which can also have its own replicas for high availability.
redis-cli -c -h node1 -p 7000 CLUSTER INFO CLUSTER SLOTS
A key's slot is computed by hashing the key (or the content inside {} braces if the key uses hash tags, which lets related keys be forced onto the same slot for multi-key operations). Clients need to be cluster-aware, since a request for a key can be redirected (via a MOVED response) to whichever node currently owns that key's slot. This design is what lets Redis Cluster scale write throughput and total dataset size well beyond a single instance's memory, at the cost of added operational complexity and some restrictions — multi-key operations only work if all involved keys map to the same slot, and numbered databases beyond database 0 aren't supported.
35. How do you connect to Redis using the CLI?
redis-cli is Redis's interactive command-line client, and connecting to a running instance is typically a single command specifying the host, port, and (if configured) authentication credentials:
redis-cli -h localhost -p 6379 redis-cli -h redis.example.com -p 6379 -a mypassword redis-cli -h localhost -p 6379 --tls # for a TLS-enabled instance
Once connected, commands can be typed interactively, or the CLI can run a single command non-interactively and exit (redis-cli GET mykey), which is convenient for scripting. Passing a password with -a on the command line is convenient but leaves the credential visible in shell history and process listings; --user combined with -a supports ACL-based authentication for a specific user rather than the legacy single-password AUTH, and reading the password from an environment variable or a config file is generally the safer approach for anything beyond quick local testing.
36. What is a Cache Penetration Problem?
Cache penetration is a performance issue where requests for non-existent data repeatedly bypass the cache and hit the backend database, causing overload, often due to malicious attacks or data deletion. Solutions involve caching null/empty results with short TTLs, using a Bloom filter to pre-check for non-existent keys, or implementing logical checks to filter invalid IDs before database queries.
37. Why is Redis often faster than a traditional relational database for caching?
The speed difference comes from where and how data is stored and accessed, not from any single trick. Redis keeps its entire working dataset in RAM, so a read or write is a direct memory access rather than a disk seek, and its data structures (hash tables, skip lists, linked lists) are purpose-built for O(1) or O(log n) operations rather than the general-purpose relational model a SQL database has to support.
- In-memory storage — no disk I/O on the read/write path for normal operations, several orders of magnitude faster than disk access.
- Simple protocol — the RESP protocol is lightweight text/binary, avoiding the parsing and planning overhead of a SQL query.
- No query planner or joins — a GET or HGET is a direct structure lookup, not a query that needs to be parsed, planned, and optimized.
- Purpose-built data structures — a Sorted Set or Hash operation maps almost directly to an efficient underlying structure, rather than being expressed through general-purpose relational tables and indexes.
The trade-off is exactly what you'd expect from those design choices: Redis isn't meant to replace a relational database for complex, ad hoc queries, multi-table joins, or datasets far larger than available RAM — it excels specifically at fast, simple key-based access to a working set that fits in memory.
38. What is Valkey, and how does it relate to Redis?
Valkey is a Linux Foundation-backed, BSD-3-Clause licensed fork of Redis, created immediately after Redis Ltd. moved the core Redis project off the permissive BSD license to a source-available dual license (SSPLv1/RSALv2) in March 2024. Valkey started from the last BSD-licensed Redis release (7.2.4) and has continued developing independently since, with contributions from major cloud vendors and several original Redis engineers, including Redis creator Salvatore Sanfilippo, who has contributed to Valkey.
| Redis (current, 8.x line) | Valkey |
| Tri-licensed: AGPLv3 (OSI-approved, added back in Redis 8, May 2025) or source-available SSPLv1/RSALv2. | BSD-3-Clause, unrestricted, OSI-approved open source, no copyleft terms. |
| Maintained by Redis Ltd. | Maintained by the Linux Foundation with a broad multi-vendor contributor base. |
| Adds newer Redis-exclusive features like vector sets (VADD/VSIM). | Its own independent roadmap; e.g. Valkey 9.x added multi-database cluster support and atomic slot migration. |
The two remain wire-protocol compatible in most respects, so standard client libraries (Jedis, Lettuce, redis-py, and others) generally work against either without code changes, which is why major managed cache services (AWS ElastiCache, Google Cloud Memorystore, among others) now default new deployments to Valkey. For teams choosing between them, the practical question usually comes down to license comfort (BSD vs AGPL/source-available) rather than a meaningful feature gap, since the two have stayed close in core capability even while diverging in governance.
39. How I/O Multiplexing Works in Redis?
Redis uses I/O multiplexing to enable its single-threaded core to efficiently handle thousands of concurrent client connections. This technique allows the Redis server to monitor multiple sockets simultaneously and process data on those that are ready, without blocking on any single connection.
- Single-threaded core
- Redis processes all commands sequentially in a single main thread, which eliminates the overhead of thread creation, context switching, locks, and race conditions.
- Non-blocking I/O
- All client sockets are set to non-blocking mode. This means that an I/O operation (read/write) returns immediately if no data is available, rather than pausing the entire thread.
- Event Loop
- The main thread runs an event loop that uses a specific I/O multiplexing system call provided by the operating system (e.g.,
epollon Linux,kqueueon macOS/BSD,evporton Solaris). - Kernel Notification
- Instead of constantly polling all connections (which wastes CPU), the event loop blocks in a single, efficient system call (like
epoll_wait). The operating system kernel is responsible for monitoring all the file descriptors (sockets) and notifying Redis when one or more of them are ready for an I/O operation. - Event Handling
- When the system call returns, Redis's event loop processes only the "ready" sockets one by one. It reads the command, executes it from memory, and writes the response back to the client.
40. What is the difference between RDB and AOF persistence?
Both write data to disk so a Redis instance can recover its dataset after a restart or crash, but they capture that data in fundamentally different forms, with different trade-offs.
| RDB | AOF |
| Point-in-time binary snapshot of the full dataset. | Append-only log of every write command, in order. |
| Faster restart, since loading one compact file is quick. | Slower restart, since the log must be replayed command by command (mitigated somewhat by AOF rewriting). |
| Can lose all writes since the last snapshot on a crash. | Can lose at most ~1 second of writes with appendfsync=everysec, or none with always. |
| Smaller file size, since it's a compacted binary snapshot. | Larger file size, though periodic rewriting keeps it from growing unbounded. |
Many production deployments run both together: RDB for fast, compact backups and quick restarts, AOF for tighter durability against a crash between snapshots. Redis merges the two on restart by preferring AOF if both are enabled, since it generally represents more recent state, falling back to RDB if AOF is disabled.
41. How does Redis achieve high throughput with a mostly single-threaded design?
Redis's core command execution has traditionally run on a single thread, which sounds like it should limit throughput, but it actually sidesteps a large class of overhead that a multi-threaded design would otherwise need to pay for.
- No lock contention — since only one thread ever touches the core data structures at a time, there's no need for mutexes or locking around reads and writes, which removes a meaningful source of overhead multi-threaded in-memory stores have to manage.
- In-memory operations are already fast — most commands complete in microseconds, so a single thread can still issue an enormous number of operations per second.
- Efficient event-driven networking — the server uses an event loop over multiplexed I/O to handle many client connections concurrently on that one thread, rather than blocking per connection.
- Predictable atomicity — because commands run one at a time with nothing else interleaved, individual commands (and MULTI/EXEC transactions) are naturally atomic with no extra coordination needed.
Modern Redis does offload some genuinely parallelizable work — like background persistence via a forked child process, and I/O threading for reading/writing client sockets in newer versions — to separate threads/processes, while keeping command execution itself single-threaded. This hybrid approach is what lets Redis claim both simplicity/atomicity and very high real-world throughput at the same time.
42. Why should you configure an eviction policy for a Redis instance used as a cache?
The default noeviction policy means once maxmemory is reached, Redis starts rejecting new write commands outright with an out-of-memory error, rather than making room by removing older data. For a pure caching use case, that's usually the wrong behavior: a cache is supposed to gracefully lose its least valuable entries under memory pressure, not stop accepting new data and start returning errors to the application.
maxmemory 2gb maxmemory-policy allkeys-lru
Configuring an eviction policy like allkeys-lru or allkeys-lfu makes the cache self-managing: as memory fills up, Redis automatically removes the least recently (or least frequently) used entries to make room, which matches how a cache is expected to behave — stale or unused data quietly falls out, while hot data stays resident. Skipping this configuration is a common cause of production incidents where a cache-only Redis instance unexpectedly starts throwing write errors under load, simply because nobody told it that eviction, not rejection, was the intended behavior when full.
43. How does Redis Cluster shard data across nodes?
Redis Cluster divides the entire keyspace into 16,384 fixed hash slots, and assigns ownership of ranges of those slots to each master node in the cluster — a 3-master cluster might own roughly 5,461 slots each, for example. A key's slot is computed as CRC16(key) mod 16384, so which node a given key belongs to is a deterministic function of the key itself, not a lookup table that has to be consulted for every single key individually.
CLUSTER KEYSLOT mykey CLUSTER ADDSLOTS 0 1 2 3 4
To let related keys be co-located for multi-key operations, Redis supports hash tags: if a key contains a substring wrapped in {}, only that substring is hashed to determine the slot, so user:{1001}:profile and user:{1001}:orders both land on the same slot despite being different keys. Slots (and their data) can be migrated between nodes for rebalancing without downtime, and a client that sends a command for a key not owned by the node it contacted gets redirected to the correct node via a MOVED response, which is why cluster-aware client libraries cache the slot-to-node mapping rather than guessing on every request.
44. When should you use Redis Sentinel instead of Redis Cluster?
The deciding factor is whether the real need is high availability for a dataset that fits comfortably on one node, or horizontal scaling across many nodes because the dataset or write throughput has outgrown a single instance.
Sentinel is the right fit when a single master's capacity (memory and throughput) is genuinely sufficient, and the goal is just automatic failover if that master goes down — it's simpler to operate, has no sharding restrictions (multi-key operations, transactions across arbitrary keys, and all 16 numbered databases work normally), and client configuration is comparatively straightforward.
Redis Cluster is the right fit once the dataset or throughput genuinely needs to span multiple masters — it adds high availability too (each master can have its own replicas, similar to Sentinel's role but built into the cluster itself), but at the cost of the sharding restrictions covered elsewhere (same-slot requirement for multi-key ops, no numbered databases beyond 0, more complex client and operational tooling).
The practical rule: don't reach for Cluster's added complexity just for high availability if a single master would otherwise be plenty — Sentinel solves that specific problem with meaningfully less operational overhead.
45. What happens when a Redis master fails in a Sentinel-managed setup?
Sentinel's failover process follows a defined sequence rather than reacting instantly to any single missed check, specifically to avoid triggering an unnecessary failover from a brief, isolated network blip.
Clients using a Sentinel-aware library discover the new master by asking Sentinel for the current address rather than hardcoding a fixed host, which is what lets an application keep working through a failover without a manual configuration change. Any writes made to the old master that hadn't yet replicated to the promoted replica at the moment of failure are lost, since Sentinel can't recover data the new master never received.
46. Explain the execution flow of a Redis transaction using MULTI/EXEC?
Unlike a database transaction that begins actual execution immediately, a Redis MULTI block queues commands on the client's connection without running them, and only EXEC triggers the whole batch to actually execute, uninterrupted.
The key nuance for interviews: a runtime error (like incrementing a key that holds a string) is different from a syntax error — runtime errors are only discovered during execution in step J, and don't stop the remaining queued commands from still running, since Redis doesn't inspect a command's effect on data until it actually executes it.
47. How can you optimize Redis memory usage for large datasets?
Since Redis keeps data in RAM, memory efficiency directly determines both cost and how much data fits on a given instance, and a handful of concrete techniques typically account for most of the achievable savings.
- Use compact encodings for small collections — Redis automatically stores small Hashes, Lists, Sets, and Sorted Sets using memory-efficient internal encodings (like
listpack) instead of full hash tables, as long as they stay under configurable size thresholds (hash-max-listpack-entries, etc.); keeping collections small where the data model allows it takes advantage of this automatically. - Choose Hashes over separate keys — storing related fields in one Hash has meaningfully less per-key overhead than the same data spread across many individual String keys.
- Use Bitmaps or HyperLogLog for large boolean/cardinality tracking instead of a Set of millions of individual entries, when the exact-membership guarantee a Set provides isn't actually needed.
- Set appropriate TTLs so stale cache data doesn't accumulate indefinitely and silently consume memory nobody's using.
- Enable an eviction policy with a maxmemory cap so memory usage has a hard, predictable ceiling rather than growing until the instance runs out of RAM.
- Analyze actual usage with MEMORY USAGE and redis-cli --bigkeys before optimizing blindly, to find which specific keys or patterns are actually consuming the most memory.
48. How do you troubleshoot high memory usage in a Redis instance?
High memory usage troubleshooting starts with distinguishing "memory usage is high but expected" from "memory usage is growing unexpectedly," since the fixes are very different.
INFO memory MEMORY DOCTOR redis-cli --bigkeys MEMORY USAGE mykey
- Check INFO memory for
used_memory,maxmemory, andmem_fragmentation_ratio— a high fragmentation ratio can mean actual data usage is much lower than the process's real memory footprint suggests. - Run redis-cli --bigkeys to sample the keyspace and identify unusually large individual keys, which are a common, easy-to-fix source of runaway memory.
- Check for missing TTLs on data that was meant to be temporary — a caching pattern that forgot to set an expiration accumulates forever.
- Review the eviction policy and maxmemory setting — if neither is configured appropriately, memory has no ceiling at all.
- Check for unbounded collection growth — a List or Set that only ever gets appended to, with nothing trimming or expiring it, is a classic slow memory leak in application logic rather than in Redis itself.
- Use MEMORY USAGE on suspect keys to confirm exactly how much a specific key is consuming, rather than guessing from aggregate stats alone.
49. Why is the maxmemory-policy setting important for a cache-only Redis deployment?
maxmemory-policy is what actually determines Redis's behavior once the configured maxmemory limit is hit, and for a cache-only deployment, getting this setting wrong can turn a memory-pressure event into an application outage rather than a graceful, expected eviction.
maxmemory 4gb maxmemory-policy allkeys-lfu
Left at the default noeviction, a cache-only instance under memory pressure starts rejecting every new write with an error, which most application code isn't written to handle gracefully — a caching layer failing writes often isn't treated as a soft, expected condition the way a cache miss is. Setting an appropriate allkeys-* policy instead means the instance quietly evicts less valuable entries to make room, keeping the cache functional and the application unaware anything unusual even happened. The choice between allkeys-lru (recency-based) and allkeys-lfu (frequency-based) matters too: LFU tends to perform better for workloads with a strong "hot set" of frequently-accessed keys, since LRU alone can be tricked by a burst of one-time accesses pushing genuinely hot keys out.
50. Explain the lifecycle of a key with a TTL set in Redis?
A key's TTL doesn't trigger a background timer that fires exactly at expiration — Redis uses a combination of lazy and active strategies to actually reclaim expired keys, which is worth understanding since it explains some otherwise-surprising behavior around memory and replication.
The propagation detail in step J matters for consistency: replicas don't independently decide a key has expired based on their own clock — the master is the source of truth for expiration, and sends an explicit DEL/UNLINK to replicas once it expires a key, which avoids replicas disagreeing about whether a key is still valid due to clock drift or replication lag.
51. How does Redis handle atomicity for multi-key operations?
A single Redis command, even one touching multiple keys (like MSET or SUNIONSTORE), is always atomic on its own — because command execution is single-threaded, nothing else can run in the middle of it. The harder case is atomicity across a sequence of separate commands, where Redis offers a few different tools depending on what's actually needed.
| Tool | Use When |
| MULTI/EXEC | A fixed, known sequence of commands needs to run uninterrupted. |
| WATCH + MULTI/EXEC | The sequence depends on first reading a value (check-then-act), needing optimistic locking. |
| Lua scripting (EVAL) | Complex conditional logic across multiple keys needs to run as one atomic unit, including branching not expressible as a flat command list. |
Lua scripts are the most powerful option here: the entire script executes as a single atomic step from Redis's perspective, with no other command interleaved anywhere in the middle, which lets you express logic (loops, conditionals, computed values feeding into further commands) that plain MULTI/EXEC can't, since MULTI/EXEC only queues a fixed list without letting one command's result influence the next command in the same transaction.
52. What is the difference between a Redis List and Sorted Set for queues?
Both can back a queue, but they fit different queue semantics depending on whether strict FIFO insertion order or a computed priority should determine processing order.
| List (LPUSH/RPOP) | Sorted Set (ZADD/ZPOPMIN) |
| Strict insertion-order FIFO (or LIFO with matching push/pop ends). | Ordered by an explicit score, which can represent priority, a timestamp, or any custom ranking. |
| Simple, minimal overhead per operation. | Slightly more overhead, since it maintains sorted order via a skip list. |
| Good fit for a plain task queue where order of arrival is all that matters. | Good fit for a priority queue, delayed queue (score = due time), or any case needing reordering. |
| BLPOP/BRPOP provide blocking pop for worker patterns. | ZPOPMIN/ZPOPMAX support similar patterns, plus range queries by score. |
The deciding question is usually: does processing order need to be anything other than strict arrival order? If yes — priority levels, a scheduled/delayed queue, or reordering based on some external factor — a Sorted Set's score gives that flexibility directly; if the queue is genuinely just first-in-first-out, a List is simpler and has less overhead per operation for the same result.
53. How do you implement a distributed lock using Redis?
The basic pattern uses a single atomic command to both acquire the lock and set a safety expiration in one step, so a crashed client can never hold a lock forever:
SET lock:resource-1 "unique-client-token" NX PX 30000
NX means the key is only set if it doesn't already exist (so only one client can "win" the lock at a time), and PX 30000 gives it a 30-second auto-expiring safety net in case the client that acquired it crashes before releasing it explicitly. Releasing the lock safely requires checking that the client releasing it is the one that actually holds it — done via a small Lua script so the check-and-delete is atomic:
if redis.call("GET", KEYS[1]) == ARGV[1] then return redis.call("DEL", KEYS[1]) else return 0 end
This basic pattern is sufficient for most single-instance use cases, but it has a known weakness against a master failing over to a replica that hadn't yet received the lock write, which is what the more elaborate Redlock algorithm (acquiring the lock across a majority of independent Redis instances) is designed to address for scenarios where lock correctness genuinely can't tolerate that edge case — though Redlock's own guarantees have been debated in the distributed-systems community, and many applications find the simpler single-instance pattern an acceptable trade-off in practice.
54. How does Redis Streams support consumer groups?
A consumer group lets multiple consumers cooperatively process a single stream, with Redis tracking, per group, which entries have been delivered and which have been explicitly acknowledged — behavior much closer to a traditional message queue than Redis's other data types offer.
XGROUP CREATE events mygroup 0 XREADGROUP GROUP mygroup consumer-1 COUNT 10 STREAMS events > XACK events mygroup 1691425200000-0
When a consumer reads with XREADGROUP, entries are added to that consumer's pending entries list (PEL) — delivered but not yet acknowledged. Calling XACK removes an entry from the PEL once processing is confirmed complete. If a consumer crashes with unacknowledged entries still in its PEL, XCLAIM (or the newer XAUTOCLAIM) lets another consumer in the same group take ownership of those stuck entries and retry them, which is what gives Streams at-least-once delivery semantics within a group — an entry isn't considered fully processed until it's explicitly acknowledged, no matter which consumer ends up handling it.
55. Which is better and why: Redis Pub/Sub or Redis Streams for event delivery?
The two solve overlapping but genuinely different problems, so "better" depends entirely on whether message durability and replay matter for the use case.
Pub/Sub is the better fit when messages are only meaningful to clients that are connected right now — live dashboards, real-time notifications, chat presence updates — where a message missed by a disconnected client is expected to simply be irrelevant by the time that client reconnects. It's simpler, has lower overhead, and needs no consumer-group bookkeeping.
Streams is the better fit whenever a message must not be silently lost if no one happens to be listening at that exact instant — event sourcing, audit logs, task queues, or any pipeline where a consumer restarting or briefly disconnecting shouldn't mean lost data. Streams' persistence, consumer groups, and per-message acknowledgment give it delivery guarantees Pub/Sub fundamentally doesn't attempt to provide.
The practical rule: reach for Pub/Sub when "only currently-listening clients need this" is actually true and acceptable; reach for Streams the moment reliable delivery, replay, or coordinated processing across multiple consumers becomes a real requirement rather than a nice-to-have.
56. How do you integrate Redis as a session store in a web application?
Using Redis for session storage means each user's session data (login state, cart contents, preferences) is stored as a Hash or JSON-serialized String under a key derived from a session ID, with a TTL matching the desired session lifetime — instead of relying on server-local in-memory session storage, which breaks as soon as requests are load-balanced across multiple application servers.
HSET session:abc123 user_id "1001" cart_items "3" EXPIRE session:abc123 1800 # 30-minute session timeout
Most web frameworks (Express with connect-redis, Spring Session with its Redis integration, Django with django-redis, and others) provide a ready-made session store adapter, so the application typically doesn't hand-roll this logic — it configures the framework to use Redis as the session backend and gets automatic session read/write/expiry wired in. The key operational benefit over local in-memory sessions is that any application server instance can serve any request for a given session, since session state lives centrally in Redis rather than pinned to whichever server first created it, which is exactly what makes horizontal scaling and rolling deployments practical for a stateful-feeling web application.
57. Explain the internal working of Redis's hash table resizing (rehashing)?
Redis's core keyspace (and large Hash-type values) are backed by a hash table, and as entries are added or removed, the table needs to grow or shrink to keep lookups close to O(1) — but a naive full rehash (allocate a new table, move every entry, free the old one) would briefly block every other operation on a table with millions of entries, which conflicts directly with Redis's single-threaded, low-latency design.
This incremental rehashing spreads the cost of a full table resize across many individual commands instead of pausing everything for one large operation, which is what lets Redis resize its hash tables even under heavy load without a noticeable latency spike. During the migration window, any lookup for a key has to check both tables (since it might not have been migrated yet), which is a small, bounded per-operation cost rather than one large blocking one.
58. How do you configure Redis persistence for a production deployment?
Production Redis persistence is typically both RDB and AOF enabled together, tuned to balance recovery speed, durability, and operational overhead, rather than relying on just one mechanism alone.
# redis.conf save 900 1 save 300 10 save 60 10000 appendonly yes appendfsync everysec auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb
The reasoning behind this common combination: RDB snapshots provide fast, compact backups useful for disaster recovery and moving data between environments, while AOF with appendfsync everysec caps potential data loss at roughly one second of writes, a durability level most applications find acceptable without the latency cost of always. auto-aof-rewrite-percentage controls when Redis automatically compacts the AOF file (once it's grown a configured percentage larger than after the last rewrite), keeping it from growing unbounded. For genuinely critical data, pairing this local persistence config with replication (so a replica also holds a full copy) is standard, since local persistence alone still leaves a gap between the last fsync and any writes since, whereas a fully synced replica offers an additional, independent copy.
59. What is the difference between Redis Cluster and client-side sharding?
Both split data across multiple Redis instances, but they differ in where the sharding logic and cluster awareness actually live.
| Redis Cluster | Client-Side Sharding |
| Sharding logic (hash slots, redirection) built into Redis and cluster-aware clients. | Sharding logic implemented entirely in application/client code, against plain standalone Redis instances. |
| Automatic slot rebalancing and MOVED redirection handled by the cluster. | Rebalancing across shards must be handled manually by the application. |
| Built-in replica-based failover per shard. | Failover must be implemented separately, e.g. pairing each shard with its own Sentinel setup. |
| Standardized behavior across any cluster-aware client library. | Sharding scheme (e.g. consistent hashing) is whatever the application chooses, requiring custom logic per client language. |
Client-side sharding predates Redis Cluster's maturity and still shows up in some existing systems or when the sharding key logic needs to be more custom than Cluster's simple hash-slot model allows, but for new deployments Redis Cluster is generally preferred since it removes the need to hand-build and maintain sharding, rebalancing, and failover logic in application code that Redis itself now handles natively.
60. How does Redis support Lua scripting for atomic operations?
Redis embeds a Lua interpreter directly in the server, and EVAL (or the cached, more efficient EVALSHA) runs a Lua script as a single atomic unit — the entire script executes with no other client command interleaved anywhere in the middle, the same guarantee a single native command gets.
-- atomic "increment if under a limit" check local current = tonumber(redis.call("GET", KEYS[1]) or "0") if current < tonumber(ARGV[1]) then return redis.call("INCR", KEYS[1]) else return -1 end
EVAL "..." 1 rate:user:1001 100
Keys the script will touch are passed explicitly via KEYS (rather than the script hardcoding key names), which matters for Redis Cluster compatibility, since the cluster needs to know up front which slots a script will access. Because the script logic runs entirely inside Redis rather than requiring a round trip back to the client between each step, it also cuts network latency for multi-step logic — a "check current value, conditionally increment" pattern that would otherwise need two separate round trips (with a race condition between them) becomes one atomic, single-round-trip operation.
61. When would you choose Redis Streams over a message broker like Kafka?
Both give you a durable, replayable, partitioned-ish log with consumer groups, but they're built for different scales and operational footprints, so the choice usually comes down to how large and how critical the messaging workload actually is.
Redis Streams makes sense when messaging is a secondary capability layered on top of a system that's already using Redis for caching, sessions, or other data — adding a Stream avoids standing up an entirely separate piece of infrastructure just for a moderate-volume event pipeline. It's also naturally in-memory (though persistable via RDB/AOF like any Redis data), giving low latency for smaller-to-moderate workloads without Kafka's operational overhead of a distributed log system with its own cluster, brokers, and tooling.
Kafka is the better choice once the workload genuinely needs Kafka-scale throughput, very long retention windows measured in weeks or months across large datasets, tiered storage for cost-effective long-term retention, or a rich ecosystem of connectors and stream-processing tools (Kafka Connect, Kafka Streams). Kafka is purpose-built and heavily optimized for exactly that scale of durable event streaming in a way Redis, fundamentally an in-memory store, isn't designed to match.
The practical rule: reach for Redis Streams when messaging needs are modest and you'd rather not run a second piece of infrastructure; reach for Kafka once volume, retention, or ecosystem requirements genuinely exceed what an in-memory-first system is built for.
62. How do you secure Redis access using ACLs?
Redis's Access Control List (ACL) system lets you define named users, each with their own password, and fine-grained permissions over which commands they can run and which keys they can touch — a meaningful step up from the older, single shared-password requirepass model, which offered no per-user distinction at all.
ACL SETUSER app-readonly on >secretpass ~cache:* +get +mget -@write ACL SETUSER app-writer on >anotherpass ~orders:* +@all -flushall -flushdb ACL LIST
The pattern above shows the key building blocks: ~pattern restricts which keys a user can access (glob-style, so ~cache:* limits the user to keys under that prefix), +command/-command grants or denies specific commands, and +@category/-@category does the same for whole command categories (like @write or @dangerous). This lets a deployment give a read-only reporting service exactly read access to its own key namespace, while a different service gets write access scoped to its own keys, with neither able to run administrative commands like FLUSHALL — a level of least-privilege access control that a single shared password can't express at all.
63. Why should the KEYS command be avoided in production?
KEYS pattern scans the entire keyspace to find matching keys, and because it runs on Redis's single command-execution thread, it blocks every other client from being served for however long that full scan takes — on a dataset with millions of keys, that can mean a multi-second (or longer) freeze of the entire instance, affecting every application using it, not just the one that ran the command.
# avoid in production KEYS user:* # use instead SCAN 0 MATCH user:* COUNT 100
SCAN is the safe alternative: it walks the keyspace incrementally, returning a small batch of keys plus a cursor per call, so the cost of a full traversal is spread across many small, non-blocking operations instead of one large blocking one — at the cost of a weaker consistency guarantee (keys added or removed during the scan may or may not be reflected, unlike KEYS's single atomic snapshot view). For production Redis, KEYS is generally reserved for one-off debugging on a non-critical instance, never for application logic or scheduled jobs, precisely because of the blocking behavior that makes it dangerous at any meaningful dataset size.
64. How do you configure Redis for cache-aside pattern usage?
The cache-aside (lazy-loading) pattern keeps the application in control of when data is read from and written to the cache, with Redis itself needing minimal special configuration — the pattern mostly lives in application logic, with a few Redis-side settings that support it well.
# pseudocode for the read path value = redis.get(cache_key) if value is None: value = database.query(...) redis.set(cache_key, value, ex=300) # cache for 5 minutes return value
maxmemory 4gb maxmemory-policy allkeys-lru
On the read side: check the cache first; on a miss, fetch from the source of truth (typically a database) and populate the cache with an appropriate TTL before returning. On the write side, the application typically writes to the database and then either updates or invalidates the corresponding cache key, rather than writing to the cache directly as the source of truth — Redis in this pattern is explicitly a derived, disposable copy, never the authoritative store. An eviction policy (as covered elsewhere) and sensible per-key TTLs are the main Redis-side configuration that keeps a cache-aside deployment healthy, since the pattern assumes cache misses are cheap and expected, not a failure condition.
65. Explain the execution flow of a Redis Cluster request with a MOVED redirection?
A cluster-aware client doesn't need to know in advance exactly which node owns every key, but it does need to handle being told it guessed wrong, which is what the MOVED response mechanism exists for.
Well-behaved cluster clients cache the slot-to-node mapping after learning it, so a MOVED redirection typically only happens once per stale mapping, not on every single request — the client corrects its cache and future requests for that slot go directly to the right node. A related response, ASK, appears specifically during live slot migration between nodes: it tells the client to retry the command against a different node for this one request only, without permanently updating its cached mapping, since the migration might not be finished yet.
66. How does Redis handle replication lag between a master and its replicas?
Redis replication is asynchronous by default: a write completes and is acknowledged to the client as soon as the master processes it, without waiting for any replica to confirm receipt — which is what makes writes fast, but also means a replica's data can lag slightly behind the master at any given moment, and that gap can widen under heavy write load or network issues.
INFO replication # master_repl_offset:12345 # slave0:...,offset=12300,lag=1
Redis exposes replication offsets on both master and replicas, and the difference between them is effectively the lag — visible via INFO replication, which is the standard way to monitor how far behind a given replica currently is. For workloads that can't tolerate reading stale data from a lagging replica, the WAIT command lets a client block until a write has been acknowledged by a specified number of replicas (with a timeout), effectively trading some of replication's default speed for a stronger consistency guarantee on that specific write, without switching the whole deployment to synchronous replication permanently. Persistent, growing lag over time is usually a sign the replica's hardware, network, or CPU can't keep pace with the master's write volume, and is treated as an operational issue to investigate rather than expected behavior.
67. Why doesn't Redis guarantee strong consistency by default across replicas?
Redis's default replication is asynchronous specifically to keep write latency low: a master acknowledges a write as soon as it's processed locally, without pausing to confirm every replica has received it too. That design choice is exactly what makes strong consistency (every replica always reflecting the latest acknowledged write) not guaranteed by default — there's an inherent window, however small, where a replica's data can be behind the master's.
The practical consequence shows up most visibly during failover: if a master fails and a replica that hadn't yet received the most recent writes is promoted (by Sentinel or Redis Cluster), those most recent writes are permanently lost, and any client that had already read them from the old master before the failure effectively saw data that no longer exists post-failover. This is a deliberate trade-off, not an oversight — Redis prioritizes latency and availability over strict consistency by default, which fits the vast majority of caching and session-storage use cases where slightly stale replica reads or an occasional lost write during a rare failover are an acceptable cost.
For workloads that need stronger guarantees, the WAIT command (blocking until a specified number of replicas acknowledge a given write) is the available lever, used selectively for specific critical writes rather than as a blanket default, since applying it to every write would erode the latency benefit that makes Redis attractive in the first place.
68. How do you mitigate a Cache Avalanche in a Redis-backed system?
A Cache Avalanche happens when a large number of cached keys expire at (or near) the same moment, sending a sudden flood of requests through to the backing database all at once, since the cache can no longer absorb them — a database that was comfortably handling load with the cache in front of it can be overwhelmed by that simultaneous mass of cache misses.
- Jitter TTLs — instead of setting every similar key to expire in exactly, say, 300 seconds, add a small random offset (e.g. 300 seconds ± 30 seconds) so expirations spread out over time rather than clustering.
- Use a mutex/lock on cache repopulation — when a popular key expires, let only one request rebuild it while others either wait briefly or serve a slightly stale value, rather than every concurrent request hammering the database for the same data simultaneously.
- Multi-tier caching — a local, short-lived in-process cache layer in front of Redis absorbs some traffic even if the Redis-level entry has just expired.
- Circuit breaking / rate limiting on the database — as a last line of defense, protect the database itself from being overwhelmed regardless of what caused the surge.
- Redis high availability (Sentinel or Cluster) — guards against the related scenario where the avalanche is caused by the Redis instance itself going down, not just mass key expiration, sending all traffic straight to the database with no cache layer at all.
69. What is the difference between Redis's diskless replication and disk-based replication?
When a new replica connects (or an existing one falls too far behind to catch up incrementally), the master needs to send it a full copy of the dataset to bootstrap from, and Redis supports two different mechanisms for producing that initial transfer.
| Disk-based Replication | Diskless Replication |
| Master writes a full RDB snapshot to a local disk file first, then transfers that file to the replica. | Master streams the RDB snapshot data directly over the network socket to the replica, without writing it to local disk first. |
| Extra disk I/O and disk space needed for the temporary snapshot file. | Avoids that disk I/O and space entirely, generating the snapshot data on the fly during transfer. |
| Can be beneficial if disk I/O is fast and network is comparatively slow, since the file is ready before transfer starts. | Beneficial when disk I/O or space is the constrained resource, e.g. on cloud instances with limited or slow local disk. |
| repl-diskless-sync no | repl-diskless-sync yes |
Diskless replication is generally the better default on modern cloud infrastructure where local disk can be a scarcer or slower resource than network bandwidth, which is why it's commonly enabled in production. repl-diskless-sync-delay adds a small configurable wait before starting a diskless sync, giving multiple replicas that connect around the same time a chance to be served by a single generated snapshot stream instead of the master redundantly generating one per replica.
