Open-Source Wikis

/

Redis

/

Redis

/

Architecture

redis/redis

Architecture

Redis is a single-process, mostly single-threaded event-driven server. The main thread runs an event loop that multiplexes all client sockets, accepts new connections, drains query buffers, executes commands against the in-memory dataset, and writes replies back. Background threads handle a small number of well-bounded jobs (fsync, lazy free, AOF rewrite child reaping) and, when enabled, IO threads handle parallel socket reads and writes. Persistence and replication run as forked child processes that share the parent's memory via copy-on-write.

This page summarises the flow from main() in src/server.c down to the data structures that hold keys and values. Each subsystem has its own page; this is the map.

Process layout

graph TD
    subgraph MainProcess[redis-server process]
      Main[Main thread<br/>aeMain event loop<br/>src/ae.c, src/server.c] -->|read/write| Net[Networking<br/>src/networking.c, src/connection.c]
      Net -->|RESP parse| Cmd[Command dispatch<br/>processCommand src/server.c]
      Cmd -->|key lookup / mutation| DB[Per-DB kvstore<br/>src/db.c, src/kvstore.c]
      DB -->|object ops| Types[Type implementations<br/>src/t_string.c .. src/t_zset.c]
      Cmd -->|notifications| Pubsub[Pub/Sub & keyspace notifications<br/>src/pubsub.c, src/notify.c]
      Cmd -->|persistence hook| AOF[AOF buffer<br/>src/aof.c]
      Cmd -->|replication hook| Repl[Replication backlog<br/>src/replication.c]
      Main -->|cron| Expire[Active expiration / eviction<br/>src/expire.c, src/evict.c]
      Main -->|cron| Defrag[Active defrag<br/>src/defrag.c]
    end

    subgraph BIO[Background bio threads]
      BIOClose[BIO_CLOSE_FILE]
      BIOFsync[BIO_AOF_FSYNC]
      BIOLazy[BIO_LAZY_FREE]
    end

    subgraph IOThreads[Optional IO threads<br/>src/iothread.c]
      IOT1[Thread 1 .. N<br/>read query buf<br/>write reply buf]
    end

    subgraph Children[Forked children]
      RDBChild[RDB save child<br/>src/rdb.c]
      AOFChild[AOF rewrite child<br/>src/aof.c]
      ReplChild[Replica diskless sync<br/>src/replication.c]
    end

    Main -->|jobs| BIO
    Main -->|hand off clients| IOThreads
    Main -->|fork()| Children

The single-threaded command dispatch is the central design choice. Because processCommand() runs on one thread, command implementations don't need locks around the dataset; they can mutate server.db[i] freely. Multi-threading is opt-in (IO threads, BIO, modules running on threads) and is carefully bounded so the dataset itself stays single-writer.

Request lifecycle

sequenceDiagram
    participant Client
    participant ae as aeMain (event loop)
    participant Net as networking.c
    participant Cmd as processCommand
    participant Type as t_*.c
    participant Out as addReply*

    Client->>ae: TCP byte arrives (epoll/kqueue)
    ae->>Net: readQueryFromClient
    Net->>Net: processInputBuffer / RESP parse
    Net->>Cmd: processCommand(c)
    Cmd->>Cmd: lookup in commandTable, ACL check, cluster check
    Cmd->>Type: c->cmd->proc(c) (e.g. setCommand)
    Type->>Out: addReplyBulk / addReplyLongLong / ...
    ae->>Net: writable -> writeToClient
    Net->>Client: bytes back over TCP

The command table is generated from src/commands/*.json into src/commands.def by utils/generate-command-code.py. Each entry binds a name to a C function (e.g. setCommand in src/t_string.c) and metadata describing arity, key positions, ACL categories, and reply schema. See Networking and RESP protocol.

Storage

Redis keeps every key in process memory inside a per-database structure called a kvstore (src/kvstore.c). A kvstore is a slot-aware vector of dict hash tables — when running in cluster mode there is one dict per slot (16384), and in standalone mode there is a single dict. Each dict entry holds an SDS string key and a robj value pointer.

graph LR
    Server[redisServer.db<br/>array of 16 redisDb] --> KV[kvstore]
    KV --> S0[slot 0 dict]
    KV --> S1[slot 1 dict]
    KV --> Sn[slot N dict]
    S0 --> Entry[dictEntry]
    Entry --> Key[sds key]
    Entry --> Val[robj *]
    Val --> Encoding{encoding}
    Encoding -->|RAW/EMBSTR/INT| Str[t_string.c]
    Encoding -->|LISTPACK/QUICKLIST| List[t_list.c]
    Encoding -->|LISTPACK/SKIPLIST| ZSet[t_zset.c]
    Encoding -->|LISTPACK/HT| Set[t_set.c]
    Encoding -->|LISTPACK_EX/HT/HFE| Hash[t_hash.c]
    Encoding -->|STREAM rax| Stream[t_stream.c]

A robj (src/object.h) is a tagged union of an encoding, a refcount, an LRU/LFU bookkeeping field, and a void *ptr. The encoding determines which underlying primitive holds the actual data: SDS, listpack, quicklist, intset, dict, ziplist (legacy), or rax. Each Redis data type chooses its encoding adaptively based on size and element width — small lists are listpacks, large ones are quicklists; small sets are intsets or listpacks, large ones are hash tables; sorted sets use a skiplist plus a dict for O(log N) by-score and O(1) by-member access.

Expiration metadata lives separately in an estore (src/estore.c) backed by an ebuckets data structure (src/ebuckets.c). Hash-field TTLs are tracked the same way per hash.

Persistence

Two persistence engines coexist:

  • RDB (src/rdb.c) snapshots the entire dataset to disk at intervals configured by save directives or on demand via BGSAVE. The snapshot is written by a forked child to keep the parent responsive.
  • AOF (src/aof.c) appends every write command to a log. The log is rewritten in the background to keep size bounded; the multi-part AOF design (src/aof.c's manifest mechanism) merges base RDB + incremental files atomically.

Replication piggybacks on both: full sync sends an RDB stream, and partial sync replays from a circular replication backlog. See Persistence and Replication.

Replication and cluster

The replication subsystem (src/replication.c) is a stream-based primary/replica protocol. Replicas can use a disk-backed full sync or a diskless sync that streams the RDB directly over the network. The primary maintains a replication backlog so reconnecting replicas can resume from an offset (PSYNC/PSYNC2). A separate "rdbchannel" replication mode opens a dedicated socket so the replica can stream the RDB on one channel while still receiving live commands on another.

Cluster mode (src/cluster.c, src/cluster_legacy.c, src/cluster_asm.c) shards keys across nodes by 16384 hash slots (CRC16(key) mod 16384). Nodes gossip via a binary cluster bus on port tcp_port + 10000. Failover, slot migration, and replica promotion are handled by the cluster code; clients learn which node owns a slot through MOVED and ASK redirections.

Sentinel

Sentinel mode (src/sentinel.c) is a separate runtime built from the same binary. When redis-sentinel is invoked (or redis-server --sentinel), the process activates a different command table, monitors a set of master/replica topologies, runs leader election, and orchestrates failover. See Sentinel.

Modules

The Module API (src/module.c, header src/redismodule.h) lets shared libraries register new commands, data types, event hooks, blocking commands, cluster messages, ACL categories, key-space functions, and more. Modules can run on the main thread or on their own threads with a "thread safe context" that locks the global mutex while holding it. See Module API.

Threads in Redis

Thread Source Role
Main src/server.c, src/ae.c Event loop, command dispatch, dataset mutation.
BIO threads (3) src/bio.c BIO_CLOSE_FILE, BIO_AOF_FSYNC, BIO_LAZY_FREE.
IO threads (N) src/iothread.c Optional. Read query buffers / write output buffers in parallel.
Threads_mngr src/threads_mngr.c Cross-thread stack capture for the watchdog and DEBUG STACK-TRACE.
Module threads src/module.c Started by modules; serialise on RedisModule_ThreadSafeContextLock.

The IO threads page explains how the main thread hands clients off and reaps them.

Tooling around the binary

  • redis-cli (src/redis-cli.c) is the interactive shell, pubsub subscriber, monitor, slot-keyspace inspector, cluster manager, and --scan/--lru-test/--bigkeys benchmark tool.
  • redis-benchmark (src/redis-benchmark.c) drives synthetic load with parallel pipelines.
  • redis-check-rdb (src/redis-check-rdb.c) and redis-check-aof (src/redis-check-aof.c) statically validate persistence files. They are symlinks to the server binary that change behaviour based on argv[0].
  • The build can also produce redis-tls.so, a loadable module providing TLS connectivity (when BUILD_TLS=module).

Where to go from here

  • Event loopaeMain, the cron, and how the server wakes up.
  • Networking — accept, read, parse, write, output buffers.
  • Persistence — RDB, AOF, multi-part AOF, repair.
  • Replication — PSYNC, diskless, rdbchannel, replica streaming.
  • Cluster — slot map, gossip, failover, redirections.
  • Memory management — eviction, expiration, defrag, lazy free.
  • Modules — load order, contexts, types, blocking.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Architecture – Redis wiki | Factory