Understanding Redis’s Reactor Pattern and I/O Multiplexing
This article explains how Redis, a single‑process single‑threaded in‑memory database, uses the Reactor pattern and various I/O multiplexing techniques such as select, poll, epoll, and kqueue to efficiently handle thousands of concurrent client connections.
Redis is an open‑source in‑memory cache database that achieves high performance despite having only about 60,000 lines of code, largely because it runs as a single‑process single‑threaded server handling client requests, persistence tasks, and other background work.
The article first describes Redis’s working model: multiple clients connect to the server, send commands like GET and SET, and the server processes them sequentially in the main thread, while auxiliary tasks such as RDB persistence and AOF rewriting are performed in forked child processes.
To understand why a single thread can handle many connections, the classic C10K problem is introduced, followed by a discussion of I/O multiplexing techniques— select, poll, epoll, and kqueue —including their system call signatures and limitations.
select(int nfds, fd_set *r, fd_set *w, fd_set *e, struct timeval *timeout)The evolution from select to poll ( struct pollfd { int fd; short events; short revents; }) and finally to state‑ful mechanisms like epoll (
int epoll_create(int size); int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);) and kqueue (
int kqueue(void); int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout);) is explained.
The Reactor pattern is then defined, consisting of Handles (file descriptors), a Synchronous Event Demultiplexer, an Initiation Dispatcher, Event Handlers, and Concrete Event Handlers. The interaction steps are listed, and a sequence diagram is described.
Applying this to Redis, the server treats client sockets as file events and periodic tasks as time events. The main thread runs an event loop (functions aeMain(), aeDeleteEventLoop()) after initializing the server with initServer(). Sample code from Redis.c shows the entry point:
int main(int argc, char **argv) { ... initServer(); ... aeMain(); ... aeDeleteEventLoop(server.el); return 0; }The article also mentions Java’s NIO and the Netty framework as practical implementations of the Reactor pattern, referencing Doug Lea’s “Scalable IO in Java”.
In summary, the piece walks through the motivation (C10K), the underlying I/O multiplexing mechanisms, the abstract Reactor architecture, and how Redis concretely employs this model to achieve efficient, event‑driven processing.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
