一个从零实现的轻量级键值存储系统,代码结构清晰、注释完整,适合学习 Redis 底层原理和网络编程。
单实例 pipeline 模式 QPS 可达 19w,基于 jemalloc 内存分配器,支持二进制安全存储。
- 高性能网络:基于 epoll 的单线程 Reactor 模型,无锁设计,轻松应对高并发连接。
- RESP 协议:完整实现 Redis 序列化协议,可直接用
redis-cli/redis-benchmark访问。 - 二进制安全:哈希表和协议层均使用显式字节长度 +
memcpy,key/value 可包含任意字节(含\0)。 - 持久化:支持 AOF 日志、RDB 快照、混合模式三种策略,通过配置文件一行切换。
- 主从复制:全量同步(FULLSYNC)+ 增量命令广播 + 断线自动重连。
- 大 value 支持:读写缓冲区按需动态扩容,无大小硬限制。
- 配置管理:INI 格式配置文件 + 命令行参数,命令行优先级更高。
- 日志分级:INFO / WARN / DEBUG 三级,可在配置文件中调整。
# 1. 克隆并编译
git clone https://github.com/NeilYuan0404/kvstore.git
cd MyKvstore
make
# 2. 启动服务(自动加载 conf/kvstore.conf)
./bin/kvstore
# 3. 用 redis-cli 连接
redis-cli -p 6379
> SET hello world
+OK
> GET hello
"world"
> DEL hello
:1调试模式(开启详细日志 + AddressSanitizer):
make DEBUG=1
./bin/kvstore| 命令 | 语法 | 说明 |
|---|---|---|
| SET | SET <key> <value> |
写入键值对,key 已存在则覆盖 |
| GET | GET <key> |
读取键值,不存在返回 $-1 |
| DEL | DEL <key> |
删除键,返回删除数量 |
| EXISTS | EXISTS <key> |
检查键是否存在,返回 0/1 |
| MOD | MOD <key> <value> |
仅当键存在时更新值 |
| SAVE | SAVE |
手动触发 RDB 快照保存 |
| PING | PING [message] |
连通性探测,返回 PONG 或回显 message |
./bin/kvstore [选项]
-p <port> 监听端口(覆盖配置文件)
-c <path> 指定配置文件路径
--persist-mode <0-3> 持久化模式(覆盖配置文件)
--slaveof <ip> <port> 以从机身份启动,连接指定主机优先级:命令行参数 > 配置文件 > 内置默认值
MyKvstore/
├── bin/ # 编译产物(kvstore 可执行文件)
├── conf/
│ └── kvstore.conf # 主配置文件
├── data/ # 持久化数据目录(.rdb / .aof)
├── dep/
│ └── jemalloc/ # 内存分配器依赖
├── doc/
│ ├── overall.excalidraw # 整体架构图
│ ├── persist.md # 持久化模块设计
│ └── replication.md # 复制模块设计
├── include/ # 公共头文件
│ ├── kvstore.h # 顶层宏定义
│ ├── server.h # Reactor 连接结构体
│ ├── kvs_base.h # 内存分配封装
│ ├── kvs_hash.h # 哈希表接口
│ ├── kvs_persist.h # 持久化接口
│ ├── kvs_replication.h # 复制接口
│ └── kvs_configure.h # 配置管理接口
├── src/
│ ├── reactor.c # epoll Reactor 事件循环
│ ├── kvstore.c # RESP 协议解析 + 命令执行
│ ├── kvs_hash.c # 哈希表存储引擎
│ ├── kvs_persist.c # AOF / RDB 持久化
│ ├── kvs_replication.c # 主从复制
│ └── kvs_configure.c # 配置文件解析 + 日志
├── test/
│ └── scripts/ # Shell 集成测试套件
└── Makefile
客户端 (redis-cli)
│ RESP 协议
▼
┌─────────────────────────────────────────────┐
│ reactor.c │
│ epoll 事件循环 — 单线程,无锁 │
│ accept_cb → recv_cb → send_cb │
└───────────────┬─────────────────────────────┘
│ 解析后的字节流
▼
┌─────────────────────────────────────────────┐
│ kvstore.c │
│ parse_resp() RESP array 解析 │
│ kvs_executor() 命令分发 │
└──────┬─────────────┬────────────────────────┘
│ │
▼ ▼
┌──────────┐ ┌──────────────┐ ┌──────────────┐
│ kvs_hash │ │ kvs_persist │ │kvs_replication│
│ 哈希存储 │ │ AOF / RDB │ │ 主从复制 │
└──────────┘ └──────────────┘ └──────────────┘
- 协议识别推迟到 kvs_protocol:所有连接在 accept 时统一走
event_register,PSYNC 握手在协议层而非 accept 层识别,避免特殊分支。 - 二进制安全贯穿全层:从 RESP
$N\r\n头到哈希表memcpy,任意字节均可安全存储。 - 从机回放防循环:从机用
g_is_loading = true包裹kvs_protocol,防止回放 master 命令时再次触发kvs_replication_feed_slaves形成广播环路。 - 非阻塞连接安全握手:
kvs_connect_master使用poll(POLLOUT)等待 TCP 三次握手完成,再发 PSYNC,避免在EINPROGRESS状态下send静默失败。
# conf/kvstore.conf
[server]
port = 6379
log_level = 1 # 1=INFO 2=WARN 3=DEBUG
[persist]
mode = 3 # 0=关闭 1=仅AOF 2=仅RDB 3=混合(默认)
rdb_file = ../data/kvstore.rdb
rdb_save_interval = 300 # RDB 自动保存间隔(秒)
rdb_min_changes = 100 # 触发自动保存的最少变更数
rdb_save_on_shutdown = true # 关闭时是否保存 RDB
aof_file = ../data/kvstore.aof
aof_rewrite_size = 1 # AOF 自动重写阈值(MB)
aof_auto_rewrite = true
[replication]
enabled = false # 开启主从复制
role = master # master 或 slave
# master_ip = 127.0.0.1
# master_port = 6379配置文件搜索顺序(优先级递减):
- 命令行
-c指定路径 ./kvstore.conf(当前目录)./conf/kvstore.conf(项目目录)~/.kvstore.conf/etc/kvstore.conf
# 运行所有集成测试
./test/scripts/run_all_tests.sh测试套件覆盖:
| 脚本 | 测试内容 |
|---|---|
test_aof.sh |
AOF 持久化写入与重放 |
test_rdb.sh |
RDB 快照保存与恢复 |
test_large_value.sh |
大 value 读写(最大 100 KB) |
test_special_chars.sh |
UTF-8、Emoji、特殊符号二进制安全测试 |
test_replication_master.sh |
主机写入同步至从机(全量 + 增量 + 删除) |
test_replication_slave.sh |
从机连接与数据接收 |
# Pipeline 模式(16 条命令/批次)
redis-benchmark -p 6379 -P 16 -n 200000 -t set,get
# 100 并发客户端
redis-benchmark -p 6379 -c 100 -n 100000 -t set,get- 公共函数:在函数上方用块注释说明用途、参数、返回值和注意事项。
- 注释优先解释 why,而非 what(代码本身说明 what)。
- 复杂逻辑块:必须有 1-2 句解释背景或限制条件。
- 使用统一标记:
TODO:未完成功能 /FIXME:已知问题 /NOTE:重要约束。
make # 确保编译无警告
./test/scripts/run_all_tests.sh # 确保所有测试通过Neil Yuan · v1.2.0