How Redis Starts: Inside the Server’s Event Loop and Reactor Model
This article walks through Redis's startup sequence, explaining how the server creates a listening socket, registers events with the aeFileEvent system, runs a single‑threaded select‑based event loop, and processes client commands using the Reactor pattern, complete with code examples and diagrams.
Macro View of the Process
When the Redis server binary (
./redis-server) is executed, the
mainfunction initializes the server, creates a TCP listening socket, registers it with
aeCreateFileEvent, and then enters the event loop via
aeMain.
<code>int main(int argc, char **argv) {
...
initServer();
...
aeCreateFileEvent(fd, acceptHandler, ...);
...
aeMain();
...
}</code>The startup can be seen as three main steps:
Step 1 – Create a TCP listening socket
The server calls
listenToPort(), which performs the classic socket‑bind‑listen sequence and returns a file descriptor.
Step 2 – Register the listening descriptor
The descriptor is added to the
aeFileEventlist via
aeCreateFileEvent()and bound to the
acceptHandlercallback.
Step 3 – Run the event loop
aeMain()repeatedly calls
aeProcessEvents(eventLoop, AE_ALL_EVENTS), using
select(IO multiplexing) to monitor all registered descriptors.
<code>void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
while (!eventLoop->stop)
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}</code>When a client connects,
acceptHandlercreates a dedicated
redisClientand registers its read event with
aeCreateFileEvent. Subsequent client commands are processed by
readQueryFromClient, which looks up the command in the
cmdTable(command pattern) and dispatches to the appropriate implementation such as
setCommand.
<code>static struct redisCommand cmdTable[] = {
{"get", getCommand, 2, REDIS_CMD_INLINE},
{"set", setCommand, 3, REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
{"setnx", setnxCommand, 3, REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
{"del", delCommand, -2, REDIS_CMD_INLINE},
{"exists", existsCommand, 2, REDIS_CMD_INLINE},
...
};</code>After executing the command, the server schedules a reply by attaching
sendReplyToClientto the client’s writable descriptor using
aeCreateFileEvent.
<code>static void addReply(redisClient *c, robj *obj) {
...
aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
sendReplyToClient, c, NULL);
}</code>This design follows the Reactor pattern: a single thread monitors I/O events, and each event is handled by a specific callback, ensuring sequential command execution without the need for locking.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
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.