Inside Redis: How Commands Are Processed by Its Event‑Driven Engine
Redis, the high‑performance in‑memory key‑value store, uses a single‑threaded event‑driven architecture that handles client connections, command parsing, execution, and reply transmission; this article explains its deployment modes, core modules, and step‑by‑step command processing flow, including code snippets and key data structures.
Redis Deployment Architectures (Macro View)
Standalone mode : a single Redis instance without HA, suitable for development or non‑critical workloads.
Master‑Slave replication : asynchronous replication from a master to one or more slaves, providing read‑write separation and redundancy.
Sentinel mode : builds on master‑slave replication by adding monitoring nodes that automatically fail over to a new master when the current master fails.
Cluster mode : data is sharded across multiple nodes using hash slots, supporting automatic fail‑over and horizontal scaling for large datasets and high concurrency.
Core Components (Micro View)
Event‑driven engine : a high‑performance network model based on I/O multiplexing (epoll/kqueue). A single thread (the reactor) processes concurrent requests, avoiding thread‑switch overhead.
Command processing layer : parses client commands, validates them, and dispatches to the appropriate function (e.g., GET, SET, HSET) for the supported data structures.
Memory management subsystem : allocates and reclaims memory, implements eviction policies such as LRU, LFU, random, or TTL‑based eviction.
Persistence module : provides RDB snapshots and AOF logs; the AOF can be rewritten to keep the log size bounded.
Monitoring & statistics : exposes metrics like used_memory, instantaneous_ops_per_sec, commandstats, and slow‑query logs for operational tuning.
Command Execution Flow
Connection establishment : the client opens a TCP connection. The event loop (ae) accepts the socket via acceptTcpHandler, creates a client object and registers a read handler.
Read & parse phase : the read event triggers readQueryFromClient. If I/O threading is enabled, the client is placed in clients_pending_read for worker threads; otherwise the main thread reads the RESP payload, resolves the command to a function pointer in redisCommandTable, and fills client->argv and client->argc.
Command execution phase : processPendingCommandsAndResetClient calls processCommand (validation), call (pre‑hooks), the actual command function (e.g., setCommand), propagate (replication/AOF), and finally addReply to queue the response.
Response sending phase : the reply is added to clients_pending_write. In the next loop iteration handleClientsWithPendingWritesUsingThreads (or the non‑threaded variant) writes the buffered reply to the client socket, registering a write event only if the buffer is not fully drained.
Key Data Structures
typedef struct aeEventLoop {
int maxfd; // highest file descriptor
aeFileEvent *events; // registered file events
aeTimeEvent *timeEventHead; // linked list of time events
aeFiredEvent *fired; // array of fired events
} aeEventLoop; void initServer(void) {
if (createSocketAcceptHandler(&server.ipfd, acceptTcpHandler) != C_OK) {
serverPanic("Unrecoverable error creating TCP socket accept handler.");
}
} void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
while (!eventLoop->stop) {
aeProcessEvents(eventLoop,
AE_ALL_EVENTS|AE_CALL_BEFORE_SLEEP|AE_CALL_AFTER_SLEEP);
}
}Reactor Model
The event loop registers two kinds of events:
File events : triggered when a socket becomes readable or writable. Handlers such as acceptTcpHandler (new connection) and readQueryFromClient (read) are registered during server startup.
Time events : periodic tasks like serverCron (default every 100 ms) that perform key expiration, persistence triggers, replication health checks, and cluster gossip.
Multi‑Threaded I/O (Redis 6.0+)
Redis can enable a pool of I/O threads. The main thread still performs command execution and event scheduling, while I/O threads handle socket reads and writes after the afterSleep hook. When a client is marked CLIENT_PENDING_READ, the read request is dispatched to an I/O thread; the result is later processed by the main thread.
Command Lookup
All command descriptors are stored in redisCommandTable. For example, the SET command is defined as:
struct redisCommand redisCommandTable[] = {
...
{"set", setCommand, -3, "write use-memory @string", 0, NULL, 1,1,1,0,0,0},
...
};Processing a Command
int processPendingCommandsAndResetClient(client *c) {
processCommand(c); // validation, ACL, memory checks
call(c); // monitor/watch hooks
c->cmd->proc(c); // actual command (e.g., setCommand)
propagate(c); // replication/AOF
addReply(c, replyObj); // queue response
} addReplyplaces the reply into clients_pending_write so that the next beforeSleep iteration can flush it.
void addReply(client *c, robj *obj) {
if (prepareClientToWrite(c) != C_OK) return;
/* reply is now in the write queue */
}Flushing Replies
int handleClientsWithPendingWritesUsingThreads(void) {
if (server.io_threads_num == 1 || stopThreadedIOIfNeeded()) {
return handleClientsWithPendingWrites();
}
/* distribute write tasks to I/O threads */
while ((ln = listNext(&li))) {
int target_id = item_id % server.io_threads_num;
listAddNodeTail(io_threads_list[target_id], c);
item_id++;
}
/* main thread processes its own slice */
listRewind(io_threads_list[0], &li);
while ((ln = listNext(&li))) {
client *c = listNodeValue(ln);
writeToClient(c, 0);
}
/* wait for other I/O threads to finish */
while (1) {
unsigned long pending = 0;
for (int j = 1; j < server.io_threads_num; j++)
pending += getIOPendingCount(j);
if (pending == 0) break;
}
/* register write events for any remaining data */
listRewind(server.clients_pending_write, &li);
while ((ln = listNext(&li))) {
client *c = listNodeValue(ln);
if (clientHasPendingReplies(c) &&
connSetWriteHandler(c->conn, sendReplyToClient) == AE_ERR) {
freeClientAsync(c);
}
}
listEmpty(server.clients_pending_write);
return 0;
}Illustrative Diagrams
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.
dbaplus Community
Enterprise-level professional community for Database, BigData, and AIOps. Daily original articles, weekly online tech talks, monthly offline salons, and quarterly XCOPS&DAMS conferences—delivered by industry experts.
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.
