一个基于C++实现的轻量级的远程的KV数据库服务,目标是以较小代码体量实现高性能事件驱动网络模型,并支持 单线程处理路径 与 多线程处理路径 两种架构模式。
MiniRedis 当前实现了 RESP 协议解析、基础 KV 命令执行、epoll 事件循环、TCP/Unix Socket 双监听、连接空闲回收、批量写回(writev)等核心能力。
- 使用
epoll构建高并发事件循环; - 使用内置
ThreadPool+LockFreeQueue预留多线程网络 IO/任务分发能力; - 使用 RESP(Redis Serialization Protocol)与
redis-benchmark对接进行压测; - 对比官方 Redis(8.0)在同测试维度下的吞吐表现。
-
网络模型
epoll统一事件池(监听 socket、客户端 socket、timerfd)。- 支持 TCP (
0.0.0.0:9736) 与 Unix Domain Socket(默认/tmp/miniredis.sock)监听。
-
协议与命令
- 支持 RESP 请求解析与标准返回封装。
- 已实现命令:
GET、SET、DEL、EXISTS、PING、BGSAVE。
-
连接管理
- 非阻塞 socket +
EPOLLIN/EPOLLOUT动态注册。 - 连接活跃时间统计,基于
timerfd的空闲连接清理。 - 输出缓冲区上限保护(
MaxPendingWriteBytes)。
- 非阻塞 socket +
-
信号统一管理
- 使用
signalfd将传统异步信号转换为文件描述符事件,统一纳入epoll事件循环处理 - 屏蔽信号(
sigprocmask),避免信号默认处理方式干扰程序流程 - 注册的信号类型:
SIGCHLD:子进程退出(用于回收BGSAVE等后台任务)SIGPIPE:写入已关闭 socket 时触发(避免进程异常退出)SIGTERM:进程终止信号(用于优雅关闭服务)
- 通过
signalfd+epoll实现:- 信号处理与网络事件统一调度
- 避免传统 signal handler 带来的异步安全问题
- 使用
-
可切换执行模型(单线程 / 多线程)
- 单线程路径:事件线程直接读写与执行(当前主路径)。
- 多线程路径:通过
ThreadPool::submitBatch()并发处理读写任务(代码中已保留调用入口,可切换)。
-
性能测试
- 提供
benchmark/compare.sh脚本,使用redis-benchmark对 MiniRedis 与官方 Redis 做并发对比。
- 提供
-
server/src/server.cpp- 服务主入口、事件循环、连接生命周期、读写处理、信号处理、命令执行调度。
-
include/common/EventPool.hppepoll封装(add/mod/del/wait)。
-
include/common/ThreadPool.hpp- 线程池与批量任务提交能力。
-
include/common/LockFreeQueue.hpp- MPSC 无锁队列,用于跨线程待处理/待关闭连接传递。
-
server/include/KvCommandEngine.hpp- 命令分发表与内存 KV 存储(
std::unordered_map<std::string, std::string>)。
- 命令分发表与内存 KV 存储(
-
include/common/Resp.hpp- RESP 协议解析器与响应包装器。
-
include/ServerConfigure.hpp- 运行时参数(监听端口、线程数、超时时间、写队列上限等)。
-
include/KeyValueDumper.hpp- 持久化能力(将当前存储的KV导出为专有的二进制数据库文件,默认文件名
miniredis.dump)。
- 持久化能力(将当前存储的KV导出为专有的二进制数据库文件,默认文件名
epoll_wait获取就绪事件;- 区分事件类型:
- 监听 fd:执行
accept4; - 定时器 fd:执行 idle 检查;
- 客户端 fd:按
EPOLLIN/EPOLLOUT分发读写。
- 监听 fd:执行
- 读路径:
recv-> 追加 query buffer -> RESP 解析 -> 入命令队列; - 命令执行:
KvCommandEngine::execute()-> 生成 RESP 回复; - 写路径:
writev批量发送回复队列; - 异常/断开/超限:进入待关闭队列并统一回收。
代码中同时存在两组处理函数:
-
单线程:
singletonThreadReadQueryBuffer(...)singletonThreadWriteReply(...)
-
多线程:
threadPoolBatchReadQueryBufferAndWait(...)threadPoolBatchWriteReplyAndWait(...)
在 eventLoop() 中目前默认启用的是单线程函数,多线程函数调用位置已预留(可通过替换调用实现切换)。
设计意义:
- 单线程路径逻辑更简单、锁竞争少;
- 多线程路径可在高连接高并发场景下提高网络读写吞吐弹性;
- 结合无锁队列可减少线程间同步开销。
PING->+PONGSET key value->+OKGET key->$<len>...或$-1DEL key [key ...]->:<removed_count>EXISTS key [key ...]->:<exists_count>BGSAVE->+OK
命令匹配由 KvCommandEngine 内部简单哈希分发完成。
- Linux(依赖
epoll/timerfd/Unix Socket) - CMake >= 3.22.1
- C++17 编译器(如 GCC 12+/Clang 12+)
git clone --recursive https://github.com/Debug-boy/MiniRedis.git
cd MiniRedis
mkdir -p build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build . -j./server/miniredis-server默认监听:
- TCP:
0.0.0.0:9736 - Unix Socket:
/tmp/miniredis.sock
./client/miniredis-cli- 系统:Ubuntu 22.04.5 LTS
- CPU:Intel(R) Xeon(R) Platinum × 1
- 核心:1 个物理 CPU,4 个物理核心,8 个逻辑核心
- 内存:16GB
测试命令:SET/GET,默认请求总数:100000,并发从 50 到 10000。
- 在低到中等并发(50~1000)范围,MiniRedis 与 Redis 8.0 吞吐基本同量级,且多组数据下 MiniRedis 略高。
- 在高并发(3000~10000)下,双方都出现回落后再趋稳,整体仍较接近。
- 结果说明 MiniRedis 当前网络与命令执行链路具备较高效率,尤其在 SET/GET 简单 KV 场景。
| 并发 | MiniRedis SET | Redis8 SET | MiniRedis GET | Redis8 GET |
|---|---|---|---|---|
| 50 | 85034.02 | 81168.83 | 84961.77 | 82372.32 |
| 100 | 83542.19 | 84033.61 | 84245.99 | 81168.83 |
| 1000 | 65359.48 | 66137.57 | 63251.11 | 61957.87 |
| 5000 | 56274.62 | 57405.28 | 57208.24 | 56915.20 |
| 10000 | 54229.93 | 57836.90 | 55463.12 | 56433.41 |
benchmark/data.txt 中出现:
ERR unknown command 'CONFIG'failed to fetch CONFIG
这是 redis-benchmark 在某些流程中会尝试获取服务端配置,而 MiniRedis 未实现 CONFIG 命令导致。
该提示 不会阻断 SET/GET 测试本身,从日志中可见吞吐结果仍已正常产出。
主要参数包括:
VERSION:当前版本号TCP_LISTEN_PORT:默认9736TCP_LISTEN_ADDRESS:默认0.0.0.0UNIX_SOCKET_FILE_PATH:默认/tmp/miniredis.sockWORKER_NET_IO_THREADS:线程池线程数CLIENT_IDLE_TIMEOUT:连接空闲超时IDLE_CHECK_INTERVAL:idle 检查间隔MAX_PENDING_WRITE_BYTES:单连接待发送队列字节上限DUMP_SAVED_BINARY_FILE_PATH: 导出的二进制文件名称
已经支持从配置文件 xxx.conf 动态加载配置,默认的配置文件 miniredis.conf
当前版本已经支持持久化能力,方式和Redis的RDB模式类似,也是将当前存储的KV导出成专有的二进制数据库文件
导出的二进制数据库文件格式大致如下,图画的一般般大致就是这个意思
|--------------------------- Header ----------------------------|
| magic(16B) | version(16B) | kvCount(8B) | timestamp(8B) |
|---------------------------- Header MD5 -----------------------|
| header_md5(16B) |
|----------------------------KV Body ---------------------------|
| key_len(8B) | key_data(...) | value_len(8B) | value_data(...) |
| key_len(8B) | key_data(...) | value_len(8B) | value_data(...) |
| .....................Other KV................................ |
|------------------------ KV Body MD5 --------------------------|
|-----------------------kvbody_md5(16B)-------------------------|
服务端载入二进制数据库文件会进行MD5校验,只有校验通过才会加载里面的KV内容
触发方式:
1.客户端主动使用`BGSAVE`
2.达到配置制定的触发策略
- 补齐更多 Redis 命令(如
MGET/MSET/INCR/EXPIRE/TTL/CONFIG)。 - 优化命令执行层:
- 支持分片哈希表;
- 并发安全策略(读写锁、分段锁或无锁结构)。
- 更换事件循环底层API为io_uring
- 增加主从功能,以及cluster
MiniRedis 当前定位为学习/实验性质的高性能服务端实现示例,并非完整替代官方 Redis。用于生产环境前,建议补齐持久化、主从复制、事务、脚本、安全鉴权等能力。