A minimal Redis server built from scratch using C++. No frameworks, no interpreters, just raw socket programming, data structures, and systems-level engineering.
SET key value
GET key
DEL key
Supports pipelined requests: fire off multiple commands without waiting for replies in between. Efficient and clean.
Instead of multithreading, this Redis clone uses a custom event loop built with poll(). Here's why:
- Threaded IO doesn't scale well for high-connection servers: C10k problem
- Memory-heavy: Each thread = stack space.
- Short-lived clients (like PHP apps) = thread churn = CPU + latency hit.
- Multi-process/threading makes worst-case latency worse.
- Modern high-perf servers (like Nginx & Redis) use event loops.
Event loop > Threads when scaling to thousands of concurrent connections.
A production implementation should replace poll() with epoll() as it stores the FDs in the kernel so that the FD args aren't copied in every itereation. Since this is a small scale implementation, I took the liberty to just use poll().
C++ gives low-level control like C, plus:
std::string,std::vector= fewer memory bugs cuz we don't wanna cleanup the custom Dynamic buffers/arrays as they would be passed around a lot.- Zero Python/Node-style abstraction overhead
- Built a custom dynamic buffer system inspired by vectors: minimal, efficient, tailored to RESP protocol parsing.
I didn't use std::unordered_map. Here's why:
- STL is throughput-optimized, not latency-safe.
- Worst-case: an insert triggers O(N) resize, pausing everything cause who needs that :O
- On resize, keys are migrated gradually, not all at once.
- Uses
calloc()overmalloc()+memset()to:- Leverage mmap-backed lazy-zeroing
- Avoid O(N) latency when initializing large memory chunks
- I used linked lists per bucket
- Benefits:
- Stable references (no pointer invalidation during resize)
- O(1) inserts and deletes
- Easier to build using intrusive data structures
Forget templates and void pointers.
I embeded structure nodes inside our data and use a container_of() macro (inspired by the Linux kernel) to access data from within a node.
- No heap allocations for structure nodes
- Better cache locality
- Enables multi-indexed data structures
- Shares nodes across collections like Sorted Sets (score + name)
- AVL Trees (for balanced Sorted Sets)
- Timers & Timeouts
- TTL & Expiration (
EXPIRE,PERSIST)
g++ -Wall -Wextra -O2 -g server.cpp hashtable.cpp murmurhash.cpp -o server
./server
g++ -Wall -Wextra -O2 -g 03_client.cpp -o client
./client
Beej’s Guide to Network Programming Using Internet Sockets by Brian “Beej” Hall along with man7 pages for detailed reference.
Network programming, data structures, and low-level C by James Smith