DEV Community

Ricky512227
Ricky512227

Posted on

Redis Interview Preparation Guide: From Basics to Hero

Everything you need to ace your Redis interview, from fundamentals to advanced topics.


Introduction

Preparing for a Redis interview? I've been there. Whether you're a senior engineer brushing up on fundamentals or someone new to Redis, I've compiled everything I wish I knew before my interviews.

This guide is based on questions I've actually faced in interviews and problems I've solved while building real systems. I've structured it in three levels: Fundamentals (must know), Intermediate (production ready), and Advanced (expert level). Each section builds on the previous one, so you can follow along at your own pace.

I'm sharing this because when I was preparing, I couldn't find one place that covered everything from basics to advanced topics in a way that made sense. Hopefully, this helps you avoid the same struggle.


LEVEL 1: FUNDAMENTALS (Must Know)

What is Redis?

Redis stands for Remote Dictionary Server. It's an in-memory data structure store that's incredibly fast:

  • Key-Value store: Data stored as key-value pairs (dictionary-like structure)
  • Multiple data types: Strings, Lists, Sets, Hashes, Sorted Sets (different types supported)
  • Persistence options: Can save to disk (memory + disk options)
  • Single-threaded: One command at a time (no race conditions)

Key Features:

  • Speed: Microsecond latency (extremely fast - stored in memory)
  • Atomic operations: Operations are all-or-nothing (no partial failures)
  • Pub/Sub: Message broadcasting (publish events and subscribe to them)
  • Transactions: Multiple commands as one unit (execute multiple commands together)
  • Replication: Master-slave setup (backup copies for high availability)

Common Use Cases:

  • Caching: Database query results, API responses (cache repeated data)
  • Session storage: User sessions (store login info for fast access)
  • Real-time analytics: Counters, leaderboards (live counts, rankings)
  • Message queues: Task queues, job processing (background jobs)
  • Rate limiting: API throttling (limit requests)

Interview Questions - Level 1

Q: What is Redis and why would you use it?

A: Redis is an in-memory data structure store (faster than milliseconds):

  • Primary use: Caching layer between application and database (reduce DB load)
  • Speed: 100K+ ops/sec possible (extremely fast - stored in memory)
  • Data structures: Not just strings - lists, sets, hashes (supports complex data types)
  • Persistence: Optional disk storage (memory + disk combination)

When to use Redis:

  • Frequently accessed data (cache repeated queries)
  • Session management (user login data)
  • Real-time features (leaderboards, counters, notifications)
  • Pub/Sub messaging (real-time events)
  • Rate limiting (limit API calls)

Q: What are Redis data types?

A: Redis supports multiple data structures:

  1. String: Simple key-value (basic type - text, numbers, binary)
SET user:1:name "John"
GET user:1:name
INCR view_count
Enter fullscreen mode Exit fullscreen mode
  1. List: Ordered collection (array-like - push/pop from both ends)
LPUSH tasks "task1"
RPUSH tasks "task2"
LPOP tasks
Enter fullscreen mode Exit fullscreen mode
  1. Set: Unique unordered collection (no duplicates - unique values)
SADD tags "python" "redis"
SMEMBERS tags
SISMEMBER tags "python"
Enter fullscreen mode Exit fullscreen mode
  1. Hash: Key-value pairs within a key (object-like - nested key-values)
HSET user:1 name "John" age 30
HGET user:1 name
HGETALL user:1
Enter fullscreen mode Exit fullscreen mode
  1. Sorted Set: Set with scores (maintains ranking - perfect for leaderboards)
ZADD leaderboard 100 "player1"
ZADD leaderboard 200 "player2"
ZRANGE leaderboard 0 -1 WITHSCORES
Enter fullscreen mode Exit fullscreen mode

Q: How does Redis achieve high performance?

A: This is a common question, and there are several factors that make Redis so fast:

  1. In-memory storage: No disk I/O for reads (direct from RAM - microseconds). This is the biggest factor - reading from RAM is orders of magnitude faster than reading from disk.

  2. Single-threaded: No context switching, no locks (simple execution model - automatic thread safety). This might sound counterintuitive, but avoiding locks and context switches actually makes Redis faster in many cases.

  3. Optimized data structures: Efficient implementations (memory-optimized structures). Redis uses carefully designed data structures that are optimized for speed.

  4. Event-driven: Non-blocking I/O (async operations - one thread handles many requests). Instead of blocking on I/O, Redis uses an event loop to handle thousands of connections efficiently.

  5. Simple protocol: Low parsing overhead (RESP protocol - simple text-based). The protocol is simple to parse, which means less CPU time spent on parsing.

Q: What is the difference between Redis and Memcached?

A:

Redis:

  • Multiple data types (strings, lists, sets, hashes, sorted sets)
  • Persistence options (RDB snapshots, AOF logs)
  • Replication and clustering (HA support - high availability)
  • Pub/Sub messaging (real-time events)
  • Transactions and Lua scripts (complex operations)
  • Single-threaded (predictable performance)

Memcached:

  • Only strings (simple key-value)
  • No persistence (memory only - data lost on restart)
  • Multi-threaded (better CPU utilization)
  • Simpler, lighter (less features, less overhead)
  • Better for simple caching (pure cache use case)

Use Redis when: Need data structures, persistence, pub/sub

Use Memcached when: Simple string caching, multi-core utilization

Q: Explain Redis persistence - RDB vs AOF.

A: This is one of those topics that trips people up. Redis has two ways to save data to disk, and they work differently:

RDB (Redis Database):

  • Point-in-time snapshots (full backup at specific time). Think of it like taking a photo of your data at a specific moment.
  • Compact binary format (compressed - storage efficient). The files are small and efficient.
  • Faster restarts (loads single file). When Redis restarts, it just loads one file.
  • Periodic saves: SAVE 900 1 (save if 1 change in 900 seconds). You can configure when snapshots happen.
  • Con: Can lose data between snapshots (data after last snapshot is lost). If Redis crashes between snapshots, you lose that data.

AOF (Append-Only File):

  • Logs every write operation (records every command - like Git log). It's like a transaction log - every command gets written down.
  • Better durability (minimum data loss - data up to latest). You're much less likely to lose data.
  • Rewritable (can compact - remove duplicates). The file can get large, but Redis can compact it.
  • appendfsync options:
    • always: Every command (slow but safe). Every write goes to disk immediately.
    • everysec: Every second (balanced - max 1 sec loss). A good middle ground.
    • no: OS decides (fast but risky). Let the OS handle it, but you might lose more data.
  • Con: Larger files, slower restarts. The files can get big, and restarting takes longer.

Best practice: Use both (RDB for backups, AOF for durability). This gives you the best of both worlds - fast backups with RDB and durability with AOF.

Q: What is Redis eviction policy?

A: When memory is full, Redis evicts keys based on policy (deletes keys when memory is full):

Eviction policies:

  1. noeviction: Return errors (doesn't delete - returns error)
  2. allkeys-lru: Remove least recently used (delete old data from all keys - most common)
  3. allkeys-lfu: Remove least frequently used (delete less frequently used data)
  4. volatile-lru: LRU among keys with TTL (from keys with expire set)
  5. volatile-lfu: LFU among keys with TTL
  6. volatile-random: Random among keys with TTL
  7. volatile-ttl: Remove keys with shortest TTL (keys expiring soon first)
  8. allkeys-random: Random removal

Common choice: allkeys-lru for cache (automatically clears least used data)

Q: How do you set expiration on keys?

A: Multiple commands for TTL (time to live):

SET key value EX 300              # Expire in 300 seconds
SET key value PX 300000          # Expire in 300000 milliseconds
SETEX key 300 value              # Set with expiration
EXPIRE key 300                   # Set expiration on existing key
TTL key                          # Check remaining time
PERSIST key                      # Remove expiration
Enter fullscreen mode Exit fullscreen mode

Use cases:

  • Session data (auto logout after inactivity)
  • Cache entries (auto refresh stale data)
  • Rate limiting (reset counters periodically)
  • OTP codes (expire after time)

LEVEL 2: INTERMEDIATE (Production Ready)

Transactions:

  • MULTI/EXEC: Group commands atomically (execute multiple commands together - all or nothing)
  • WATCH: Optimistic locking (check then update - avoid race condition)
  • DISCARD: Cancel transaction (like rollback)

Pub/Sub:

  • PUBLISH/SUBSCRIBE: Message broadcasting (publish events and subscribe)
  • PSUBSCRIBE: Pattern-based subscriptions (wildcard patterns)
  • Channels: Topic-based messaging (like topics - specific channels)

Pipelining:

  • Batch commands: Reduce network round-trips (send multiple commands together)
  • Performance: Massive throughput increase (reduces RTT overhead)

Lua Scripts:

  • EVAL: Execute Lua code in Redis (server-side logic)
  • Atomic execution: Script runs atomically (no interruption in middle)
  • EVALSHA: Cached scripts (call using script hash - efficient)

Replication:

  • Master-Slave: Read replicas (write to master, read from slaves)
  • Asynchronous: Eventual consistency (not immediate sync - slight delay)
  • Replication lag: Slaves may be behind (monitor this)
  • Read scaling: Distribute reads across slaves

Redis Sentinel:

  • High availability: Automatic failover (detects master failure)
  • Monitoring: Watches master and slaves (continuous monitoring)
  • Automatic promotion: Promotes slave to master (when master fails)
  • Quorum: Requires multiple sentinels (consensus needed)

Redis Cluster:

  • Sharding: Data distributed across nodes (horizontal scaling)
  • Hash slots: 16384 slots distributed (keys mapped to slots)
  • Automatic failover: Node failure handling (self-healing)
  • No single point of failure: Distributed architecture

Interview Questions - Level 2

Q: Explain Redis transactions with MULTI/EXEC.

A: Transactions execute multiple commands atomically (multiple commands together - can't be interrupted):

MULTI              # Start transaction
SET balance:1 100  # Queue command
DECR balance:1     # Queue command
INCR balance:2     # Queue command
EXEC               # Execute all
Enter fullscreen mode Exit fullscreen mode

Key points:

  • Commands are queued, not executed immediately (only execute after EXEC)
  • All-or-nothing execution (all run or all fail)
  • Other clients blocked during execution (transaction runs, others wait)

With WATCH (Optimistic locking):

WATCH balance:1    # Monitor key
val = GET balance:1
# ... check value ...
MULTI
SET balance:1 new_val
EXEC               # Fails if balance:1 changed
Enter fullscreen mode Exit fullscreen mode

Use cases:

  • Atomic operations (multiple commands must succeed together)
  • Conditional updates (check then set)
  • Financial transactions (debit/credit together)

Q: What is Redis pipelining and when to use it?

A: Pipelining sends multiple commands without waiting for responses (send batch - saves RTT):

Without pipelining:

Client: GET key1
Server: value1
Client: GET key2
Server: value2
Total: 2 round trips (two network travels - slow)
Enter fullscreen mode Exit fullscreen mode

With pipelining:

Client: GET key1; GET key2; GET key3
Server: value1; value2; value3
Total: 1 round trip (one send - fast)
Enter fullscreen mode Exit fullscreen mode

Example (Python):

pipe = redis.pipeline()
pipe.set('key1', 'value1')
pipe.set('key2', 'value2')
pipe.get('key1')
results = pipe.execute()  # All at once
Enter fullscreen mode Exit fullscreen mode

Use when:

  • Multiple independent operations (related commands)
  • Network latency is bottleneck (high RTT)
  • Bulk operations (many commands at once)

Performance: 10x-100x faster than individual commands (eliminates RTT overhead)

Q: How does Pub/Sub work in Redis?

A: Pub/Sub enables message broadcasting (publishers send, subscribers receive):

Publisher:

PUBLISH notifications "New user signup"
PUBLISH logs:error "Database connection failed"
Enter fullscreen mode Exit fullscreen mode

Subscriber:

SUBSCRIBE notifications logs:error  # Waits for messages
Enter fullscreen mode Exit fullscreen mode

Pattern matching:

PSUBSCRIBE logs:*  # Pattern matching (all logs:* channels)
Enter fullscreen mode Exit fullscreen mode

Characteristics:

  • Fire-and-forget (messages not stored - delivered then forgotten)
  • No message queue (offline subscribers miss messages)
  • Multiple subscribers (all receive same message)
  • Real-time delivery (instant - no delay)

Use cases:

  • Real-time notifications (chat, alerts)
  • Event broadcasting (system events)
  • Cache invalidation (distributed cache update)
  • Microservices communication (event-driven)

Q: Explain Redis Lua scripting.

A: Lua scripts run server-side atomically (execute on server - atomic + fast):

EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 mykey myvalue
Enter fullscreen mode Exit fullscreen mode

Benefits:

  1. Atomic execution: No interruptions (no commands in middle)
  2. Reduced network: Complex logic in one call (avoid multiple round trips)
  3. Consistent: Logic guaranteed same (client logic doesn't vary)

Example - Rate limiting:

local key = KEYS[1]
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call('GET', key) or "0")

if current < limit then
    redis.call('INCR', key)
    redis.call('EXPIRE', key, 60)
    return 1
else
    return 0
end
Enter fullscreen mode Exit fullscreen mode

Use cases:

  • Atomic operations (complex multi-step operations)
  • Rate limiting (check + increment atomically)
  • Conditional updates (check-then-set patterns)
  • Complex calculations (multiple operations together)

EVALSHA for efficiency:

SCRIPT LOAD "return redis.call('GET', KEYS[1])"
# Returns: sha1_hash

EVALSHA sha1_hash 1 mykey  # Use hash instead of script
Enter fullscreen mode Exit fullscreen mode

Q: How does Redis replication work?

A: Master-slave replication for high availability (master copy to slaves - backup + read scaling):

Setup:

# On slave
REPLICAOF master-host 6379
Enter fullscreen mode Exit fullscreen mode

How it works:

  1. Slave connects to master (connection established)
  2. Master sends RDB snapshot (initial data copy)
  3. Master sends command stream (continuous updates)
  4. Asynchronous replication (slaves lag slightly - eventual consistency)

Benefits:

  • Read scaling: Slaves handle reads (read requests can go to slaves)
  • High availability: Failover to slave (master down, promote slave)
  • Data safety: Multiple copies (backups - less data loss)

Limitations:

  • Writes only to master: Slaves read-only (write only to master)
  • Replication lag: Slaves slightly behind (few milliseconds delay)
  • Manual failover: Need Sentinel for automatic (Redis Sentinel needed for auto failover)

Monitoring replication:

INFO replication  # Check replication status
# master_repl_offset - master's offset
# slave_repl_offset - slave's offset
# Difference = lag
Enter fullscreen mode Exit fullscreen mode

Q: What is Redis Sentinel?

A: Sentinel provides high availability and monitoring (automatic failover - master down, promote slave):

Features:

  1. Monitoring: Check master/slave health (continuous health check)
  2. Notification: Alert on failures (notify on problems)
  3. Automatic failover: Promote slave to master (automatic master change)
  4. Configuration provider: Clients get current master (clients get current master info)

Architecture:

  • Multiple Sentinel instances (quorum for decisions - majority vote)
  • Monitors Redis instances (all masters and slaves)
  • Consensus-based failover (majority agree before failover)

Setup:

# sentinel.conf
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 10000
Enter fullscreen mode Exit fullscreen mode

Client usage:

from redis.sentinel import Sentinel

sentinel = Sentinel([
    ('sentinel1', 26379),
    ('sentinel2', 26379),
    ('sentinel3', 26379)
])

# Always gets current master
master = sentinel.master_for('mymaster')
# Read from slaves
slave = sentinel.slave_for('mymaster')
Enter fullscreen mode Exit fullscreen mode

Q: How do you implement caching patterns with Redis?

A: Common caching strategies:

1. Cache-Aside (Lazy Loading):

def get_user(user_id):
    # Try cache first
    user = redis.get(f"user:{user_id}")
    if user:
        return user

    # Cache miss - fetch from DB
    user = db.query(f"SELECT * FROM users WHERE id={user_id}")

    # Store in cache
    redis.setex(f"user:{user_id}", 3600, user)
    return user
Enter fullscreen mode Exit fullscreen mode

Pros:

  • Only cache what's needed (cache used data only)
  • Simple to implement

Cons:

  • Cache miss penalty (first time is slow - DB query)
  • Potential stale data (if updated elsewhere)

2. Write-Through:

def update_user(user_id, data):
    # Update DB
    db.update(f"UPDATE users SET ... WHERE id={user_id}")

    # Update cache
    redis.setex(f"user:{user_id}", 3600, data)
Enter fullscreen mode Exit fullscreen mode

Pros:

  • Cache always fresh (consistent data)
  • No stale data issues

Cons:

  • Write latency (need to update both - slower)
  • More writes (both DB and cache)

3. Write-Behind (Write-Back):

def update_user(user_id, data):
    # Update cache immediately
    redis.setex(f"user:{user_id}", 3600, data)

    # Queue DB write asynchronously
    queue.push({'type': 'user_update', 'id': user_id, 'data': data})
Enter fullscreen mode Exit fullscreen mode

Pros:

  • Fast writes (immediate response)
  • Better write performance

Cons:

  • Potential data loss (if crash before DB write)
  • More complex (need async queue)
  • Eventual consistency (DB may lag)

4. Refresh-Ahead:

def get_user(user_id):
    user = redis.get(f"user:{user_id}")
    ttl = redis.ttl(f"user:{user_id}")

    # Refresh if expiring soon
    if ttl < 300:  # Less than 5 minutes left
        # Refresh in background
        async_refresh(user_id)

    return user
Enter fullscreen mode Exit fullscreen mode

Pros:

  • Always fresh (proactive refresh)
  • No cache miss penalty

Cons:

  • More complex (background refresh logic)
  • May refresh unnecessarily

Q: How do you handle cache invalidation?

A: Multiple strategies:

1. TTL-based:

redis.setex("key", 3600, value)  # Expires in 1 hour
Enter fullscreen mode Exit fullscreen mode
  • Simple, automatic (no manual intervention)
  • May serve stale data (until expiration)

2. Event-based:

def update_user(user_id, data):
    db.update(user_id, data)
    redis.delete(f"user:{user_id}")  # Invalidate cache
Enter fullscreen mode Exit fullscreen mode
  • Fresh data guaranteed (cache cleared on update)
  • Requires application logic (explicit handling)

3. Version-based:

version = redis.incr("user:version")
redis.set(f"user:{user_id}:v{version}", data)
Enter fullscreen mode Exit fullscreen mode
  • Multiple versions coexist (old + new both exist)
  • Complex to manage (version tracking)

4. Pub/Sub broadcast:

redis.publish("cache:invalidate", f"user:{user_id}")
Enter fullscreen mode Exit fullscreen mode
  • Distributed invalidation (all servers notified)
  • All instances update (cluster-wide consistency)

LEVEL 3: ADVANCED (Expert Level)

Q: Explain Redis Cluster architecture.

A: Redis Cluster provides sharding and HA (data distributed for high availability):

Architecture:

  • Hash slots: 16384 slots (keys distributed based on hash)
  • Nodes: Minimum 3 masters (data split across masters)
  • Replication: Each master has slaves (backup + failover)
  • No proxy: Clients connect directly (smart clients route to correct node)

Key distribution:

HASH_SLOT = CRC16(key) mod 16384
Enter fullscreen mode Exit fullscreen mode

Keys with same hash tag go to same node:

{user:1}:profile
{user:1}:settings
# Both go to same node (hash tag: user:1)
Enter fullscreen mode Exit fullscreen mode

Failover:

  1. Slave detects master failure (health check continuous)
  2. Majority of masters vote (quorum required)
  3. Promote slave to master (automatic promotion)

Limitations:

  • No multi-key operations across slots: Transactions only work within single slot
  • Resharding is manual: Moving slots requires manual intervention
  • Client must be cluster-aware: Must calculate CRC16 and connect to correct node

Setup:

# redis-cluster.conf
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
Enter fullscreen mode Exit fullscreen mode

Client usage:

from redis.cluster import RedisCluster

rc = RedisCluster(
    startup_nodes=[
        {"host": "127.0.0.1", "port": "7000"},
        {"host": "127.0.0.1", "port": "7001"},
    ],
    decode_responses=True
)
Enter fullscreen mode Exit fullscreen mode

Q: How do you monitor and troubleshoot Redis?

A: Multiple monitoring approaches:

1. INFO command:

INFO server      # Server info
INFO stats       # Statistics
INFO memory      # Memory usage
INFO replication # Replication status
Enter fullscreen mode Exit fullscreen mode

2. SLOWLOG:

SLOWLOG GET 10   # Last 10 slow commands
CONFIG SET slowlog-log-slower-than 10000  # Log commands > 10ms
Enter fullscreen mode Exit fullscreen mode

3. Key metrics to monitor:

  • Latency: redis-cli --latency (response time)
  • Memory: used_memory, used_memory_peak (RAM usage)
  • Hit rate: keyspace_hits / (keyspace_hits + keyspace_misses) (cache effectiveness)
  • Evictions: evicted_keys (memory pressure indicator)
  • Connections: connected_clients (client connections)
  • Replication lag: master_repl_offset - slave_repl_offset (slave delay)

4. Tools:

  • Redis Exporter + Prometheus + Grafana (metrics visualization)
  • RedisInsight (GUI tool - real-time monitoring)
  • redis-stat (command-line tool)

Common issues:

  • High latency: Slow commands, blocking operations, swap
  • Memory issues: No eviction policy, memory leaks, large keys
  • Connection spikes: Connection pool exhaustion
  • Replication lag: Network issues, slow queries

Q: What are Redis memory optimization techniques?

A: Multiple strategies to reduce memory:

1. Choose right data structures:

# Instead of multiple keys
SET user:1:name "John"
SET user:1:email "john@example.com"

# Use hash (more efficient - single key)
HSET user:1 name "John" email "john@example.com"
Enter fullscreen mode Exit fullscreen mode

2. Use hash encoding:

CONFIG SET hash-max-ziplist-entries 512
CONFIG SET hash-max-ziplist-value 64
Enter fullscreen mode Exit fullscreen mode

Small hashes stored efficiently (ziplist - memory compact)

3. Set TTL on everything:

SETEX key 3600 value  # Auto cleanup
Enter fullscreen mode Exit fullscreen mode

4. Use compression:

  • Compress values before storing (client-side compression)
  • Trade CPU for memory (need to decompress when using)

5. Avoid large keys:

  • Split large values into smaller chunks (like pagination)
  • Use sorted sets instead of large lists

6. Monitor memory:

MEMORY USAGE key  # Memory used by key
MEMORY STATS      # Memory statistics
Enter fullscreen mode Exit fullscreen mode

Q: How do you implement rate limiting with Redis?

A: Multiple approaches:

1. Fixed Window:

def is_allowed(user_id, limit=10):
    key = f"rate:{user_id}:{time.time() // 60}"  # Per minute
    count = redis.incr(key)
    redis.expire(key, 60)
    return count <= limit
Enter fullscreen mode Exit fullscreen mode
  • Simple, but edge case: burst at window boundary

2. Sliding Window (Token Bucket):

local key = KEYS[1]
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local now = tonumber(ARGV[3])

redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
local count = redis.call('ZCARD', key)

if count < limit then
    redis.call('ZADD', key, now, now)
    redis.call('EXPIRE', key, window)
    return 1
else
    return 0
end
Enter fullscreen mode Exit fullscreen mode
  • Accurate, smooth limiting (requests spread evenly)

3. Leaky Bucket:

def is_allowed(user_id, limit=10, window=60):
    key = f"rate:{user_id}"
    pipe = redis.pipeline()
    now = time.time()

    # Remove old entries
    pipe.zremrangebyscore(key, 0, now - window)
    # Count remaining
    pipe.zcard(key)
    # Add current request
    pipe.zadd(key, {now: now})
    # Set expiration
    pipe.expire(key, window)

    results = pipe.execute()
    return results[1] < limit
Enter fullscreen mode Exit fullscreen mode

Q: How do you handle Redis failover in production?

A: Multi-layered approach:

1. Redis Sentinel Setup:

# 3+ Sentinel instances for quorum
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 10000
Enter fullscreen mode Exit fullscreen mode

2. Client configuration:

from redis.sentinel import Sentinel

sentinel = Sentinel([
    ('sentinel1', 26379),
    ('sentinel2', 26379),
    ('sentinel3', 26379)
], socket_timeout=0.1)

# Always gets current master
master = sentinel.master_for('mymaster', socket_timeout=0.1)

# Read from slaves
slave = sentinel.slave_for('mymaster', socket_timeout=0.1)
Enter fullscreen mode Exit fullscreen mode

3. Application resilience:

  • Connection pooling (reuse connections)
  • Retry logic with exponential backoff (retry on failures)
  • Circuit breaker pattern (stop on repeated failures)
  • Graceful degradation (continue without cache if Redis is down)

4. Monitoring:

  • Continuous health checks (track uptime)
  • Alert on failover events (notifications)
  • Track replication lag (slaves catching up)
  • Monitor client connections (connection spikes)

Q: What are common Redis anti-patterns?

A:

  1. Large keys: Storing huge values (>1MB) blocks Redis (split into smaller chunks)
  2. KEYS command in production: Scans all keys (use SCAN instead - non-blocking)
  3. Unbounded lists: Lists growing infinitely (use LTRIM to limit)
  4. Hot keys: Single key accessed by everyone (shard or replicate)
  5. No expiration: Keys never expire (memory fills up - set TTL)
  6. Synchronous operations: Blocking commands (use async, pipelining)
  7. Connection per request: Expensive (use connection pool)
  8. No monitoring: Can't debug issues (metrics mandatory)

REAL INTERVIEW SCENARIOS

Challenge 1: Implement distributed lock

import redis
import uuid
import time

class RedisLock:
    def __init__(self, redis_client, key, timeout=10):
        self.redis = redis_client
        self.key = f"lock:{key}"
        self.timeout = timeout
        self.identifier = str(uuid.uuid4())

    def acquire(self):
        end_time = time.time() + self.timeout
        while time.time() < end_time:
            if self.redis.set(self.key, self.identifier, nx=True, ex=self.timeout):
                return True
            time.sleep(0.001)
        return False

    def release(self):
        # Lua script for atomic check-and-delete
        lua_script = """
        if redis.call("get", KEYS[1]) == ARGV[1] then
            return redis.call("del", KEYS[1])
        else
            return 0
        end
        """
        self.redis.eval(lua_script, 1, self.key, self.identifier)

# Usage
lock = RedisLock(redis_client, "resource:123")
if lock.acquire():
    try:
        # Critical section
        process_resource()
    finally:
        lock.release()
Enter fullscreen mode Exit fullscreen mode

Challenge 2: Leaderboard with Redis Sorted Set

class Leaderboard:
    def __init__(self, redis_client, name):
        self.redis = redis_client
        self.key = f"leaderboard:{name}"

    def add_score(self, player, score):
        self.redis.zadd(self.key, {player: score})

    def increment_score(self, player, amount):
        self.redis.zincrby(self.key, amount, player)

    def get_rank(self, player):
        # Rank (0-based, descending)
        rank = self.redis.zrevrank(self.key, player)
        return rank + 1 if rank is not None else None

    def get_top(self, n=10):
        return self.redis.zrevrange(self.key, 0, n-1, withscores=True)

    def get_around(self, player, radius=2):
        rank = self.redis.zrevrank(self.key, player)
        if rank is None:
            return []
        start = max(0, rank - radius)
        end = rank + radius
        return self.redis.zrevrange(self.key, start, end, withscores=True)
Enter fullscreen mode Exit fullscreen mode

Challenge 3: Session management

import json
from datetime import timedelta

class SessionManager:
    def __init__(self, redis_client, timeout=3600):
        self.redis = redis_client
        self.timeout = timeout

    def create_session(self, session_id, user_data):
        key = f"session:{session_id}"
        self.redis.setex(key, self.timeout, json.dumps(user_data))

    def get_session(self, session_id):
        key = f"session:{session_id}"
        data = self.redis.get(key)
        if data:
            # Refresh TTL on access
            self.redis.expire(key, self.timeout)
            return json.loads(data)
        return None

    def update_session(self, session_id, user_data):
        key = f"session:{session_id}"
        if self.redis.exists(key):
            self.redis.setex(key, self.timeout, json.dumps(user_data))
            return True
        return False

    def delete_session(self, session_id):
        key = f"session:{session_id}"
        self.redis.delete(key)
Enter fullscreen mode Exit fullscreen mode

QUESTIONS TO ASK THE INTERVIEWER

Technical:

  1. "What's your Redis deployment setup? Standalone, Sentinel, or Cluster?"
  2. "How do you handle cache invalidation strategies?"
  3. "What's your approach to Redis persistence (RDB/AOF)?"
  4. "How do you monitor Redis performance and health?"
  5. "What's your Redis version and upgrade strategy?"

Operational:

  1. "How do you handle Redis failover and disaster recovery?"
  2. "What's your strategy for memory management and eviction?"
  3. "How do you handle Redis backups and restore procedures?"
  4. "What's the typical Redis workload (read/write ratio)?"
  5. "How do you ensure Redis security (auth, encryption)?"

QUICK PREP CHECKLIST

Day 1-2: Basics

  • [ ] Data types and commands
  • [ ] Persistence (RDB/AOF)
  • [ ] Expiration and eviction
  • [ ] Build simple cache

Day 3-4: Intermediate

  • [ ] Transactions and pipelining
  • [ ] Pub/Sub messaging
  • [ ] Lua scripting
  • [ ] Implement rate limiter

Day 5-6: Advanced

  • [ ] Replication and Sentinel
  • [ ] Redis Cluster
  • [ ] Performance tuning
  • [ ] Build distributed lock

Day 7: Review

  • [ ] Review concepts
  • [ ] Practice scenarios
  • [ ] Prepare questions

Conclusion

Redis is a powerful tool that goes far beyond simple caching. Understanding its data structures, persistence options, and advanced features will help you build scalable systems and ace your interviews.

The key is to practice. Set up a local Redis instance, try the examples in this guide, and build something with it. The more hands-on experience you have, the more confident you'll be in interviews and production environments.

Good luck with your Redis interviews!


Recommended Resources

Official Documentation

Books

  • "Redis in Action" by Josiah Carlson - Comprehensive guide with real-world examples
  • "The Little Redis Book" by Karl Seguin - Quick introduction to Redis concepts

Practice

  • Set up a local Redis instance and experiment with commands
  • Build a caching layer for your application
  • Implement rate limiting, session management, and leaderboards
  • Try the coding challenges in this guide

Related Articles


Top comments (0)