Redis: Single-Threaded Logic, Multi-Threaded Power
Redis is one of the most widely used systems in modern backend architecture. Especially for caching, you’ll find Redis sitting quietly in the critical path of high-performance systems.
The “Single-Threaded” Design
Most modern systems scale by throwing more threads at the problem, leveraging multiple CPU cores to process work in parallel.
Redis does the opposite.
It processes commands using a single-threaded event loop.
The Redis Paradox
If Redis is single-threaded…
How does it handle tens of thousands of concurrent connections?
Shouldn’t it become a bottleneck?
This is where the real insight lies:
Redis is single-threaded at the application layer, but powered by a massively parallel system underneath which is the Operating System.
Think of Redis not as doing everything itself, but as a smart coordinator that delegates heavy lifting to the OS.
1. The Kernel’s Parallel “Watcher” Team
When you have thousands (or even 100,000+) connections, Redis does not actively monitor each one.
While Redis is idle, the Operating System is doing a lot of work behind the scenes using all CPU cores.
It:
- Reads incoming network data
- Figures out which connection (socket) it belongs to
- Stores it in the right place
When data is ready for a connection, the OS simply marks it as:
“This one is ready to be processed.”
All such ready connections are added to a common list (called the epoll ready list).
2. The epoll “Ready List” (The OS To-Do Queue)
Think of this as a to-do list maintained by the OS.
Get utsav’s stories in your inbox
Join Medium for free to get updates from this writer.
Whenever any connection has data:
- It gets added to this list
- Multiple CPU cores can keep adding items to it at the same time
So even with thousands of connections, the OS efficiently keeps track of only the ones that matter right now.
3. I/O Multiplexing: The Bridge
This is the key idea.
- The OS prepares a list of “ready” work (in parallel)
- Redis simply picks items from that list (one by one). This is done using a system call like
epoll_wait(), which returns only the ready connections.
So instead of checking every connection, Redis just asks:
“Tell me which ones are ready.”
And processes only those.
🍴 Think of it like a restaurant:
- The OS is the host taking orders from thousands of customers in parallel
- The epoll list is the queue of ready orders
- Redis is the chef picking one order at a time
The chef never runs around checking tables, he just works off the queue.
Why This Architecture Works So Well
Redis doesn’t try to parallelize everything. It parallelizes the right parts.
- Parallelism: handled by the OS (network, I/O readiness)
- Serialization: handled by Redis (command execution)
It’s a classic example of separation of concerns done right.
The Real Bottleneck: When the Chef Gets Stuck
Think of Redis as a master chef in a kitchen.
- The OS is the delivery team bringing ingredients at lightning speed
- The chef (Redis) processes orders one at a time
This works beautifully until the chef gets stuck on one complex dish.
That’s exactly what happens with long-running commands.
Example: KEYS *
Commands like:
KEYS *- Large
SORT - Heavy Lua scripts
can block the event loop.
And when that happens:
- No other request gets processed
- Latency spikes for all clients
Even though the OS is still doing its job perfectly, Redis becomes the bottleneck.
🧠 Final Thought
Redis challenges a common assumption in system design:
You don’t always need multi-threading in your application to achieve massive concurrency.
By leveraging the operating system effectively, Redis achieves:
- Simplicity of single-threaded design
- Power of multi-core hardware









