Back to All Concepts
DatabaseCachingPerformanceSystem DesignIn-MemoryAdvanced

Redis Internals: Why is it Fast?

Deep dive into Redis architecture: single-threaded event loop, data structures, persistence strategies (RDB/AOF), replication, and cluster mode.

Last updated: By the ScaleWiki Editorial Team

The Speed of Single-Threaded Design

Redis handles 100,000+ requests/second on a single core. It's widely known to be Single-Threaded.

  • Question: How can it be fast if it uses only 1 CPU core?
  • Answer: Because it's I/O Bound, not CPU Bound. Accessing RAM is fast (nano-seconds). The bottleneck is waiting for the Network.

The Event Loop (I/O Multiplexing)

Redis works like Node.js:

  1. One main thread runs an infinite loop.
  2. It uses OS primitives (epoll on Linux, kqueue on Mac) to watch thousands of connections.
  3. When a socket is readable (client sent command), the kernel wakes up Redis.
  4. Redis reads, processes, writes response, and moves to the next socket.
  5. Zero Context Switch: No expensive thread creation/switching costs.

Visual Flow:

Client 1 ---\
Client 2 ----\
Client 3 ------> [epoll] --> Redis Main Thread (processes one at a time)
Client 4 ----/                ↓
Client 5 ---/            Response Queue → Clients

Note: Since Redis 6.0, it uses threaded I/O just for parsing network packets, but command execution is still single-threaded and atomic.

Data Structures (C Implementation)

Redis isn't just a "key-value store". It's a data structure server.

String (SDS - Simple Dynamic String)

c
struct sdshdr {
    int len;      // Current length
    int free;     // Remaining space
    char buf[];   // Actual string
};

Why custom? Faster than C strings (no strlen() O(n) traversals), pre-allocated space for appends.

Commands:

redis
SET user:123:name "Alice"
GET user:123:name  # O(1)
INCR counter       # Atomic increment

Hash (Ziplist or Hash Table)

Small hashes use ziplist (packed array, memory-efficient).
Large hashes use hash table (standard key-value).

redis
HSET user:123 name "Alice" age "30" city "NYC"
HGET user:123 name  # O(1)
HGETALL user:123     # Returns all fields

When to use: Store objects with multiple fields (user profiles).

List (Linked List or Ziplist)

redis
LPUSH queue:tasks "task1" "task2" "task3"
RPOP queue:tasks  # Get from right (FIFO queue)
LPOP queue:tasks  # Get from left (stack)

Use case: Message queues, activity feeds.

Set (Hash Table or Intset)

redis
SADD tags:post123 "redis" "database" "nosql"
SISMEMBER tags:post123 "redis"  # O(1) membership test
SINTER tags:post1 tags:post2     # Set intersection

Use case: Tags, unique visitors, recommendations.

Sorted Set (Skip List + Hash Table)

Maintains elements in sorted order:

redis
ZADD leaderboard 100 "Alice" 95 "Bob" 120 "Charlie"
ZRANGE leaderboard 0 2   # Top 3: Charlie, Alice, Bob
ZRANK leaderboard "Alice"  # Get rank (O(log n))

Use case: Leaderboards, priority queues, range queries.

Internal structure: Skip list (O(log n) insert/search) + hash table (O(1) score lookup).

Persistence (Durability)

Redis is in-memory. If you pull the plug, data is lost unless you configure persistence:

A. RDB (Redis Database Snapshot)

  • Mechanism: Every X minutes, fork the process and dump all RAM to a .rdb file.
  • Pros: Compact file. Fast startup (just load .rdb).
  • Cons: Data loss window. If crash 1 min after last snapshot, lose 1 min of writes.

Configuration:

redis
save 900 1      # Save if 1 key changed in 900 seconds
save 300 10     # Save if 10 keys changed in 300 seconds  
save 60 10000   # Save if 10k keys changed in 60 seconds

B. AOF (Append Only File)

  • Mechanism: Log every write command (SET a 1, INCR counter) to a file immediately.
  • Pros: Minimal data loss (fsync every 1 sec or every command).
  • Cons: File grows huge. Replay is slow on startup.

Configuration:

redis
appendonly yes
appendfsync everysec  # Fsync every second (balanced)
appendfsync always    # Fsync every command (slowest, safest)
appendfsync no        # OS decides (fastest, least safe)

AOF Rewrite: Redis periodically compacts the AOF file by replaying it into a new snapshot.

C. Hybrid (Recommended)

Use RDB for backups + AOF for recent writes.

redis
aof-use-rdb-preamble yes  # AOF file starts with RDB snapshot, then incremental commands
StrategyData LossStartup SpeedFile Size
RDB onlyMinutesFastSmall
AOF (always)MinimalSlowLarge
AOF (everysec)~1 secondMediumMedium
Hybrid~1 secondFastMedium

Replication (High Availability)

Redis uses leader-follower (master-replica) replication:

Setup:

Master (writes + reads)
  ↓ replication stream
Replica 1 (read-only)
Replica 2 (read-only)

How it works:

  1. Replica connects to master
  2. Master sends RDB snapshot
  3. Master streams subsequent write commands in real-time

Commands:

redis
# On replica
REPLICAOF 192.168.1.100 6379

# On master - check connected replicas
INFO replication

Eventual Consistency: Replicas lag slightly behind master (milliseconds to seconds depending on load).

Cluster Mode (Horizontal Scaling)

Redis Cluster shards data across multiple masters using hash slots:

  • 16,384 hash slots (0-16383)
  • Each master owns a subset of slots
  • Keys are hashed: HASH_SLOT = CRC16(key) mod 16384

Example 3-master cluster:

Master 1: slots 0-5460
Master 2: slots 5461-10922
Master 3: slots 10923-16383

Querying:

redis
SET user:123 "Alice"  
# Redis calculates hash slot for "user:123"
# Routes request to the appropriate master

Resharding: Move slots between nodes for load balancing.

High Availability: Each master has 1+ replicas. If master fails, replica promotes.

Pipelining (Network Optimization)

Normal request is RTT (Round Trip Time) bound:

Client → Server: GET key1 (50ms)
Server → Client: value1 (50ms)
Total: 100ms per command (max 10 ops/sec!)

Pipelining: Send multiple commands at once

python
import redis
r = redis.Redis()

pipe = r.pipeline()
pipe.get('key1')
pipe.get('key2')
pipe.get('key3')
results = pipe.execute()  # Send all 3 at once!

# Only 1 RTT instead of 3

Performance: 10x-100x throughput improvement.

Memory Management

Eviction Policies

When Redis hits maxmemory, it evicts keys:

redis
maxmemory 2gb
maxmemory-policy allkeys-lru  # Evict least recently used keys

Policies:

  • noeviction: Return errors when full
  • allkeys-lru: Evict any LRU key
  • volatile-lru: Evict LRU keys with TTL
  • allkeys-random: Random eviction
  • volatile-ttl: Evict keys expiring soonest

Memory Optimization

redis
# Estimate memory usage
MEMORY USAGE key1

# Get memory stats
INFO memory

Tips:

  • Use short key names (u:123 instead of user:id:123)
  • Use hashes for objects (more memory-efficient than multiple keys)
  • Set TTLs to auto-expire old data

Real-World Usage Examples

Twitter: Timeline Caching

redis
# Store user's timeline (list of tweet IDs)
LPUSH timeline:user:123 tweet_id_999 tweet_id_998
LRANGE timeline:user:123 0 49  # Get top 50 tweets

# Use Redis for 400M+ users
# Replicated for read scalability

Instagram: Counting & Sets

redis
# Followers count
INCR user:123:followers_count

# Check if user A follows user B
SISMEMBER followers:user_A user_B_id

# Intersection: mutual followers
SINTER followers:user_A followers:user_B

Uber: Geospatial Queries

redis
# Add driver location
GEOADD drivers 13.361389 38.115556 "driver:1"

# Find drivers within 5km
GEORADIUS drivers 15 37 5 km WITHDIST

# Redis Geospatial uses sorted sets internally

Performance Benchmarks

Typical throughput (single instance):

  • GET/SET: 100,000+ ops/sec
  • HGET/HSET: 80,000+ ops/sec
  • LPUSH/LPOP: 90,000+ ops/sec

Latency (P99):

  • Under 1ms for most commands
  • O(N) commands (KEYS, SMEMBERS) can block the server!

Common Pitfalls

⚠️ Using KEYS in production: KEYS scans all keys, blocking single-threaded Redis. Use SCAN instead.

⚠️ Large values: Storing 10MB values hurts performance. Keep values < 1MB.

⚠️ No index on sorted set score: Sorted sets don't support range queries on members, only scores.

⚠️ Blocking operations: BLPOP, BRPOP block connections. Use with care.

Interview Tips 💡

  1. Explain single-threaded model: "Redis uses event loop + epoll for 100k connections on 1 core because it's I/O bound"
  2. Data structures: "Redis provides 5 main types - strings, hashes, lists, sets, sorted sets - each optimized in C"
  3. Persistence trade-off: "RDB for fast restarts, AOF for durability, hybrid for both"
  4. Replication: "Master-replica for HA, eventual consistency with millisecond lag"
  5. Cluster: "16,384 hash slots distributed across masters for horizontal scaling"
  6. Real example: "Twitter caches 400M timelines in Redis for sub-millisecond reads"

Redis vs Memcached

FeatureRedisMemcached
Data structures5 types (string, hash, list, set, zset)Only strings
PersistenceRDB + AOFNone
ReplicationYes (built-in)No
ClusteringYes (Redis Cluster)No
Atomic operationsYes (INCR, etc.)Limited
Use caseCache + data storePure cache

Related Concepts

About ScaleWiki

ScaleWiki is an interactive educational platform dedicated to demystifying distributed systems, software architecture, and system design. Our mission is to provide high-quality, technically accurate resources for software engineers preparing for interviews or solving complex scaling challenges in production.

Read more about our Editorial Guidelines & Authorship.

Educational Disclaimer: The architectural patterns and system designs discussed in this article are based on common industry practices, technical whitepapers, and public engineering blogs. Actual implementations in enterprise environments may vary significantly based on specific product requirements, legacy constraints, and evolving technologies.

Related Articles