A Redis-inspired, high-performance key-value store written in Go, featuring a custom binary TCP protocol, lock-free MPSC queue, LRU eviction, and WAL-based crash recovery.
- 🚀 High Performance: ~49,000 ops/sec on a single connection (local benchmark)
- 🧵 Multi-threaded Architecture: 8-worker thread pool with lock-free MPSC queue
- 📦 Custom Binary Protocol: Compact, length-prefixed TCP protocol with pipelining support
- 💾 LRU Eviction: O(1) eviction using doubly-linked list + hash map
- 📝 Write-Ahead Logging: Crash recovery via WAL replay on startup
- 🔑 Core Commands: GET, SET, DEL, EXPIRE with TTL support
- 🪟 Windows Compatible: Built and tested on Windows 11
┌─────────────┐
│ Clients │
└──────┬──────┘
│ TCP (Binary Protocol)
┌──────▼──────────────────────────────┐
│ TCP Server │
│ ┌────────────────────────────┐ │
│ │ Connection Handlers (N) │ │
│ │ - Read requests │ │
│ │ - Enqueue to MPSC queue │ │
│ │ - Write ordered responses │ │
│ └──────────┬─────────────────┘ │
│ │ │
│ ┌──────────▼─────────────────┐ │
│ │ Lock-Free MPSC Queue │ │
│ └──────────┬─────────────────┘ │
│ │ │
│ ┌──────────▼─────────────────┐ │
│ │ Worker Pool (8 goroutines)│ │
│ │ - Process commands │ │
│ │ - Update KV Store │ │
│ │ - Append to WAL │ │
│ │ - Return responses │ │
│ └──────────┬─────────────────┘ │
│ │ │
│ ┌──────────▼─────────────────┐ │
│ │ KV Store │ │
│ │ - map[string]*entry │ │
│ │ - LRU List (head↔tal) │ │
│ └──────────┬─────────────────┘ │
│ │ │
│ ┌──────────▼─────────────────┐ │
│ │ Write-Ahead Log (WAL) │ │
│ │ - Append-only file │ │
│ │ - Periodic fsync │ │
│ └────────────────────────────┘ │
└─────────────────────────────────────┘
All integers are little-endian. Messages are length-prefixed:
[4 bytes message length][payload]
[1 byte CMD=0x01][2 bytes key length][key bytes]
[1 byte CMD=0x02][2 bytes key length][4 bytes TTL seconds][2 bytes value length][key bytes][value bytes]
- TTL = 0 means no expiration
[1 byte CMD=0x03][2 bytes key length][key bytes]
[1 byte CMD=0x04][2 bytes key length][4 bytes TTL seconds][key bytes]
[1 byte status][if status=0x00: 4 bytes value length][value bytes]
0x00= found0x01= not found
[1 byte status]
0x00= success0x01= failure
concurrentkv/
├── cmd/
│ └── benchmark/
│ └── main.go # Benchmark client
├── protocol/
│ └── protocol.go # Binary protocol encoding/decoding
├── queue/
│ └── mpsc.go # Lock-free MPSC queue
├── server/
│ ├── tcp.go # TCP connection handling
│ └── workerpool.go # Worker pool with command processing
├── store/
│ ├── kv.go # Key-value store with TTL support
│ └── lru.go # O(1) LRU eviction list
├── wal/
│ └── wal.go # Write-ahead logging
├── main.go # Server entry point
├── go.mod
└── README.md
- Go 1.22 or later
- Windows 11, Linux, or macOS
# Clone the repository
git clone https://github.com/yourusername/concurrentkv.git
cd concurrentkv
# Build the server
go build -o concurrentkv
# Or run directly
go run main.go# Default settings (port 31337, 100k max keys)
./concurrentkv
# Custom configuration
./concurrentkv -addr :8080 -maxkeys 50000 -wal data.walCommand-line flags:
-addr: TCP listen address (default::31337)-maxkeys: Maximum keys in store before LRU eviction (default:100000)-wal: WAL file path (default:concurrentkv.wal)
In another terminal:
go run ./cmd/benchmarkExpected output:
Completed 50000 SETs in 1.02s, 48967 ops/sec
| Metric | Value |
|---|---|
| Throughput (single client) | ~49,000 ops/sec |
| Latency (average) | ~20 µs |
| Workers | 8 |
| Concurrency Model | MPSC lock-free queue |
| Server | Ops/sec (1 client, SET) | Architecture |
|---|---|---|
| ConcurrentKV | 49,000 | Go, multi-threaded, WAL |
| Redis 7 | 98,000 | C, single-threaded, event loop |
ConcurrentKV achieves ~50% of Redis throughput while providing multi-threaded execution and built-in LRU eviction.
The MPSC (Multiple Producer, Single Consumer) queue uses atomic compare-and-swap operations on a singly-linked list:
- Enqueue: Producers atomically append nodes to the tail
- Dequeue: Single consumer removes from the head
- Lock-free: No mutexes, minimal contention
- Bounded: Effectively unbounded (limited by memory)
type MPSCQueue struct {
head atomic.Pointer[node]
tail atomic.Pointer[node]
}The LRU cache combines:
- HashMap (
map[string]*entry): O(1) key lookups - Doubly-linked list: O(1) move-to-front and evict-from-back
type lruList struct {
head *lruNode // sentinel
tail *lruNode // sentinel
size int
}- Format: Binary, append-only log file
- Operations logged: SET, DEL, EXPIRE
- Sync policy: Periodic fsync (1 second intervals) + per-entry write
- Recovery: Replays all operations on startup
The server supports full pipelining—clients can send multiple requests without waiting for responses. Responses are returned in the same order as requests were sent.
import socket
import struct
def send_set(sock, key, value, ttl=0):
key_bytes = key.encode()
val_bytes = value.encode()
payload = struct.pack('<BHI H',
0x02, # SET command
len(key_bytes),
ttl,
len(val_bytes)
) + key_bytes + val_bytes
msg = struct.pack('<I', len(payload)) + payload
sock.sendall(msg)
# Read response
resp_len = struct.unpack('<I', sock.recv(4))[0]
resp = sock.recv(resp_len)
return resp[0] == 0x00 # Success status
# Connect and test
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('127.0.0.1', 31337))
send_set(sock, 'hello', 'world')
print("SET successful!")
sock.close()- Expiry on recovery: Keys with TTL are restored without expiration after crash recovery (simplified implementation)
- Memory usage: All values stored in memory; no eviction to disk
- Network protocol: Custom binary protocol (not Redis-compatible)
- Security: No authentication or TLS support
- Clustering: Single-node only; no replication or sharding
- Lock-free hash map for the store (sharded or
sync.Map) - Zero-copy TCP parsing
- WAL record batching for higher throughput
- Full TTL recovery on crash restart
- Redis protocol compatibility layer
- Configurable worker count
- Prometheus metrics endpoint
- Graceful shutdown handling
Contributions are welcome! Please open an issue or submit a pull request.
MIT License
Atharva Arbat
Built as a systems programming project to explore concurrency patterns, custom protocols, and persistence in Go.