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:
- One main thread runs an infinite loop.
- It uses OS primitives (
epollon Linux,kqueueon Mac) to watch thousands of connections. - When a socket is readable (client sent command), the kernel wakes up Redis.
- Redis reads, processes, writes response, and moves to the next socket.
- 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)
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:
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).
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)
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)
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:
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
.rdbfile. - 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:
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:
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.
aof-use-rdb-preamble yes # AOF file starts with RDB snapshot, then incremental commands
| Strategy | Data Loss | Startup Speed | File Size |
|---|---|---|---|
| RDB only | Minutes | Fast | Small |
| AOF (always) | Minimal | Slow | Large |
| AOF (everysec) | ~1 second | Medium | Medium |
| Hybrid | ~1 second | Fast | Medium |
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:
- Replica connects to master
- Master sends RDB snapshot
- Master streams subsequent write commands in real-time
Commands:
# 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:
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
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:
maxmemory 2gb maxmemory-policy allkeys-lru # Evict least recently used keys
Policies:
noeviction: Return errors when fullallkeys-lru: Evict any LRU keyvolatile-lru: Evict LRU keys with TTLallkeys-random: Random evictionvolatile-ttl: Evict keys expiring soonest
Memory Optimization
# Estimate memory usage MEMORY USAGE key1 # Get memory stats INFO memory
Tips:
- Use short key names (
u:123instead ofuser: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
# 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
# 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
# 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 💡
- Explain single-threaded model: "Redis uses event loop + epoll for 100k connections on 1 core because it's I/O bound"
- Data structures: "Redis provides 5 main types - strings, hashes, lists, sets, sorted sets - each optimized in C"
- Persistence trade-off: "RDB for fast restarts, AOF for durability, hybrid for both"
- Replication: "Master-replica for HA, eventual consistency with millisecond lag"
- Cluster: "16,384 hash slots distributed across masters for horizontal scaling"
- Real example: "Twitter caches 400M timelines in Redis for sub-millisecond reads"
Redis vs Memcached
| Feature | Redis | Memcached |
|---|---|---|
| Data structures | 5 types (string, hash, list, set, zset) | Only strings |
| Persistence | RDB + AOF | None |
| Replication | Yes (built-in) | No |
| Clustering | Yes (Redis Cluster) | No |
| Atomic operations | Yes (INCR, etc.) | Limited |
| Use case | Cache + data store | Pure cache |
Related Concepts
- Caching Strategies — Write-through, write-back patterns
- Database Replication — Leader-follower replication
- Consistent Hashing — Distributed key placement
- LSM Trees — Alternative storage engine
- Eviction Policies — LRU, LFU strategies
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
LSM Trees (Database Internals)
Log-Structured Merge Trees: The data structure powering write-heavy databases like Cassandra, RocksDB, and DynamoDB.
Document Databases
The most popular type of NoSQL database. Storing data in flexible, JSON-like documents with embedded structures and dynamic schemas.
Caching Overview
High-speed data storage to reduce latency. The single most effective way to scale read-heavy systems.