Redis: under the hood
How does the Redis server work?
I was curious to learn more about Redis’s internals, so I’ve been familiarizing myself with the source, largely by reading and jumping around in Emacs. After I had peeled back enough of the onion’s layers, I realized I was trying to keep track of too many details in my head, and it wasn’t clear how it all hung together. I decided to write out in narrative form how an instance of the Redis server starts up and initializes itself, and how it handles the request/response cycle with a client, as a way of explaining it to myself, hopefully in a clear fashion. Luckily, Redis has a nice, clean code base that is easy to read and follow along. Armed with a TAGSfile, my $EDITOR
, and GDB, I set out to see how it all works under the hood. (Incidentally, I was working with the Redis code base as ofcommit b4f2e41. Of course, internals such as I outline below are subject to change. However, the broad architecture of the server is unlikely to change very much, and I tried to keep that in mind as I went along.)
This article examines server startup and takes a high-level view of the request/response processing cycle. In a subsequent article, I’ll dive in to greater detail and trace a simple SET
/GET
command pair as they make their way through Redis.
Startup
Let’s begin with the main()
function in redis.c
.
Beginning global server state initialization
First, initServerConfig()
is called. This partially initializes a variable server
, which has the type struct redisServer
, that serves as the global server state.
// redis.h:338 struct redisServer { pthread_t mainthread; int port; int fd; redisDb *db; // ... }; // redis.c:69 struct redisServer server; /* server global state */
There are a huge number of members in this struct, but they generally fall into the following categories:
- general server state
- statistics
- configuration from config file
- replication
- sort parameters
- virtual memory config, state, I/O threads, & stats
- zip structure
- event loop helpers
- pub/sub