Skip to content
Back to all concepts
DatabaseCachingPerformanceSystem Design

Redis Internals: Why is it Fast?

Single-threaded Event Loop, RDB vs AOF Persistence, and Pipelining.

By ScaleWikiUpdated 2 min readAdvanced

The Speed of Single-Threaded Design

Redis commonly executes ordinary commands on a main thread while using additional threads or processes for other work. Throughput depends on commands, values, clients, persistence, and hardware.

  • Question: How can it be fast if it uses only 1 CPU core?
  • Answer: An event loop avoids one thread per connection, and in-memory operations can be inexpensive. Network bandwidth, command CPU cost, memory, or persistence may become the bottleneck.

Event Loop

Redis Single-Threaded Event Loop

Queued Commands
Waiting for requests...
Main Thread
Idle
0
Ops Done

Notice: Even though Redis uses I/O Multiplexing to handle thousands of connections, it executes commands sequentially. Durations here are exaggerated for visibility. A slow command (like KEYS *) blocks the entire server for everyone.

  1. One main thread runs an infinite loop.
  1. Reduced per-connection overhead: Event-driven multiplexing avoids a thread per client; it does not eliminate operating-system context switches.

Trade-off: Blocking commands (e.g., KEYS *) freeze all clients.


Persistence

RDB (Snapshot)

  • Every X minutes, fork and dump all RAM to .rdb file.
  • Pro: Fast restarts.
  • Con: Lose minutes of data if crash.

AOF (Append Only File)

  • Log every write command to a file.
  • Pro: Minimal data loss.
  • Con: Slow restarts (replay log).

Config:

appendonly yes
appendfsync everysec  # Balanced: ~1 sec loss

Pipelining

Problem: Network Round Trips are expensive.

Without pipelining:

1 command → wait 50ms → 1 result
(max 20 ops/sec)

With pipelining:

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

Result: Fewer round trips can improve throughput. Measure the gain at realistic batch sizes; very large batches add buffering and latency.


Data Structures

Redis isn't just Key-Value. It's a Data Structure Server:

  • String: SET counter 1, INCR counter
  • Hash: HSET user:123 name "Alice"
  • List: LPUSH queue task1, RPOP queue
  • Set: SADD tags "redis", SISMEMBER tags "redis"
  • Sorted Set: ZADD leaderboard 100 "Alice", ZRANGE leaderboard 0 9

Memory Management

Eviction Policies (when maxmemory is hit):

  • allkeys-lru: Evict least recently used keys
  • volatile-ttl: Evict keys with soonest expiration
  • noeviction: Reject writes that require more memory when the limit is reached; reads can continue
maxmemory 2gb
maxmemory-policy allkeys-lru

Interview Tips

  • Why single-threaded? "An event loop multiplexes connections. Benchmark command cost and network limits rather than assuming a universal requests-per-second figure."
  • Persistence trade-off: "RDB for fast restarts, AOF for durability, or hybrid (RDB + AOF incremental)."
  • Use cases: "Session storage, leaderboards (sorted sets), pub/sub messaging."
  • Blocking commands: "Avoid KEYS in production. Use SCAN instead."

Sources and verification

Redis benchmarking, pipelining, and persistence provide the implementation context. Test a realistic command mix while a background save is running; a GET-only benchmark does not establish write durability or worst-case latency.