Redis Architecture
Redis is not a black box that magically returns strings.
Introduction
Redis is not a black box that magically returns strings. Under the hood it is a single-threaded C program built around an event loop, a hash-table keyspace, and typed value encodings chosen for memory efficiency.
Production incidents — latency spikes during BGSAVE, memory fragmentation, replica lag — only make sense when you understand how the event loop, jemalloc allocator, and fork-based persistence interact.
This lesson maps the major components so you can reason about bottlenecks before you reach for more hardware.
Understanding the topic
Key concepts
- aeEventLoop (epoll/kqueue) multiplexes thousands of TCP connections on one thread.
- redisObject wraps every value with type, encoding, and LRU/LFU metadata.
- The keyspace is a dict mapping string keys to redisObject pointers.
- Encodings switch automatically — intset for small sets, listpack for compact hashes.
- Background children handle RDB fork, AOF rewrite, and lazy freeing (Redis 4+).
- Modules and I/O threads (Redis 6+) extend the core without changing atomic command semantics.
flowchart TBClient -->|RESP| EventLoopEventLoop --> CommandTableCommandTable --> KeyspaceKeyspace --> Background[BG: AOF RDB repl]Background --> Disk
Step-by-step explanation
- Client data arrives on a socket; the event loop marks it readable.
- Input buffer is parsed into a command array (argv).
- Command lookup table dispatches to the C handler (e.g. setCommand).
- Handler reads/writes redisObject structures in the keyspace dict.
- Reply is buffered in the client output queue and flushed when writable.
- Periodic tasks expire keys, replicate to replicas, and fsync AOF.
Syntax reference
Common commands
- INFO server — version and process stats.
- OBJECT ENCODING — see how Redis stores a key internally.
- INFO memory — fragmentation ratio >1.5 warrants investigation.
INFO server # redis_version, uptime, tcp_portINFO memory # used_memory, fragmentationINFO stats # instantaneous_ops_per_secOBJECT ENCODING mykey # int, embstr, listpack, etc.
Informative example
Inspect internal encoding after inserting data — small integers use special encodings:
SET counter 42OBJECT ENCODING counter# "int"SET big "a" repeated 1000 timesOBJECT ENCODING big# "embstr" or "raw" depending on size
Redis picks encodings transparently. Knowing them explains why HSET on a tiny hash is cheaper than storing JSON.
Real-world use
Real-world use cases
- Diagnosing why BGSAVE causes latency spikes (fork + copy-on-write).
- Choosing hash vs string based on encoding thresholds.
- Sizing instances knowing single-threaded command throughput ceiling.
- Planning module or I/O thread usage in Redis 7 deployments.
- Explaining replica lag as replication backlog + network, not magic.
Best practices
- Disable transparent huge pages on Linux Redis hosts.
- Monitor used_memory_rss vs used_memory for fragmentation.
- Keep maxmemory below physical RAM to leave headroom for fork.
- Use lazyfree-lazy-user-del for large key deletes.
- Upgrade to supported Redis versions for security and encoding improvements.
- Profile with LATENCY DOCTOR after architecture changes.
Common mistakes
- Assuming more CPU cores speed up command throughput on one instance.
- Running BGSAVE on memory-heavy nodes without understanding COW pressure.
- Ignoring encoding transitions when values grow past thresholds.
- Treating Redis like a multi-threaded database for write scaling.
Advanced interview questions
Q1BeginnerWhat is the Redis event loop?
Q2BeginnerWhat is redisObject?
Q3IntermediateWhy does BGSAVE cause latency spikes?
Q4IntermediateWhat are Redis encodings?
Q5AdvancedHow would you scale writes beyond one Redis node?
Summary
Redis = event loop + keyspace dict + typed encodings.