Redis Under the Hood: Why and How it Uses a Single-Threaded Architecture
Why is Redis Single-Threaded?
To understand why Redis uses one thread, we first have to understand the drawbacks of using many.
- The Overhead of Multi-Threading: In traditional multi-threaded servers, a new thread is often spun up to handle every new client connection. This introduces significant complexity because operations like incrementing a variable are not naturally thread-safe. If two threads try to update the same value simultaneously, data corruption can occur. To prevent this, databases use pessimistic locking mechanisms like mutexes and semaphores to protect critical sections of code. These locks unnecessarily block threads that are otherwise ready to execute, creating bottlenecks. Multi-threaded code is also notoriously bug-prone, harder to reason about, and sacrifices stability.
- The Power of Atomicity: By keeping command execution single-threaded, Redis guarantees that every command you run is completely atomic. When a command is executing, no other command can interrupt it, meaning there are no costly context switches. You can perform complex operations-like a set union or an increment-without ever worrying about race conditions or needing locks, guaranteeing data correctness.
How Does a Single Thread Handle Multiple Connections?
If a single thread fires a standard network read request, it usually blocks the entire thread until the client actually sends data, bringing the whole server to a halt. Redis avoids this blocking problem using two key concepts: I/O Multiplexing and an Event Loop.
- I/O Multiplexing: Instead of blindly waiting for a network socket to send data, Redis uses a technique called I/O multiplexing, which allows the operating system to monitor multiple socket connections simultaneously. Redis utilizes high-performance system calls-like
epollon Linux,kqueueon Mac, orevportin Solaris-to monitor thousands of connections in constant time. Redis is only notified when a socket actually has data ready to be read, eliminating idle waiting.
Illustration of IO Multiplexing & Single-threaded execution (Credit: ByteByteGo)
- The Event Loop (Reactor Pattern): Redis implements a "Reactor" design pattern to manage these connections. The single thread runs in a continuous event loop where it accepts incoming TCP connections, uses the operating system to check which sockets have data ready, reads the command from a ready socket, executes the command, and then immediately moves to the next ready socket. Everything from accepting connections to executing commands happens within this one seamless loop.
Illustration of Reactor Pattern in Multiplexing
Why is this Architecture So Fast?
Redis perfectly balances the slow nature of network communication with the extreme speed of computer memory.
- In-Memory Speed: Because Redis stores its data entirely in memory rather than on a hard disk, it bypasses the severe speed limitations of disk I/O. When the event loop receives a command, processing it is just a pure memory operation (like updating a node in a tree or adding a value to an array), which is incredibly fast.
Illustration of in-memory data storage (Credit: ByteByteGo)
- Exploiting the Network Bottleneck: Network I/O (waiting for clients to send data) is the slowest part of the process. By using I/O multiplexing to handle the slow network part concurrently, the single thread is kept constantly fed with ready-to-execute commands. Because the actual execution of these commands in memory takes practically no time, the thread can clear the queue of commands rapidly without getting bogged down.
- Optimized Data Structures: Since Redis doesn't have to worry about persisting data to disk during every operation, it utilizes highly efficient, low-level data structures like skip lists, linked lists, and hash tables. It also utilizes a custom internal type system (
redisObject) to execute these specific operations as efficiently as possible.
Illustration of efficient lower-level data structures (Credit: ByteByteGo)
(Note: The core technical explanation, diagrams, and structure in this post are adapted from the excellent article Let's dance on the Redis floor.)