基于多线程与协程的 Redis 协议 KV 服务,支持原生分页存储和可插拔存储引擎。
English · 软件架构 · 文档导航 · 兼容性 · 阶段进展
PKV 使用 C++ 实现,通过 ACL 的线程与协程处理并发连接,以流式解析器接收请求,并提供 RESP2 / RESP3 响应。当前核心是 String、List、Hash、Set、ZSet 的原生有界页存储:命令通过统一的数据访问层操作根记录和私有页,底层可选择内存、RocksDB 或 WiredTiger。
项目仍在完善 Redis 服务端兼容性。命令注册、局部回归通过或实时复制可用,均不代表完整 Redis 替代能力;部署前请阅读能力边界。
普通命令共享执行准入,并通过键锁协调数据访问;EXEC 等需要隔离的操作使用独占准入。命令语义、分页存储和具体引擎分层实现。详细的请求路径、源码入口和提交边界见中文架构文档(English)。
| 方向 | 已实现的能力 | 进一步阅读 |
|---|---|---|
| 并发与协议 | 多线程、ACL 协程 I/O、流式解析、pipeline、HELLO 协商 RESP2/RESP3 | RESP3、命令分发 |
| 原生分页 | 五种基础类型;String 小值内联、大值分块;集合使用有界节点和片段 | 存储布局、格式与旧数据 |
| 事务与批量 | MULTI/EXEC、WATCH;符合条件的单库原生 EXEC 通过工作区一次提交;原生批量读写 | 事务、源端提交、批量保证 |
| 多数据库 | 连接级 SELECT、按需创建逻辑库、跨库 COPY 和原生 MOVE | 逻辑库、MOVE |
| 过期与键空间 | 毫秒级期限、条件过期、索引式主动过期、SCAN、DBSIZE、RANDOMKEY | 主动过期、SCAN |
| 扩展数据操作 | Bitmap / BITFIELD、HyperLogLog、GEO、阻塞 List/ZSet、本地 Pub/Sub | 功能导航 |
| 认证与诊断 | AUTH、命名 ACL 用户与文件持久化、ACL LOG、CLIENT、INFO、部分 CONFIG | 权限、INFO、配置 |
| 实时复制 | 私有 PKV2–PKV5 流;页事务、整组 EXEC、有序页编辑及内存 MOVE 重放 | 复制边界 |
需要 CMake 3.10+、C/C++ 编译器(默认 C++17,可选 C++11)、ACL 的 acl_all / fiber_cpp / fiber、xxHash 0.8.0+、zlib 和线程库。开发头文件和库必须可被 CMake 找到。redis-cli 用于下方交互示例,Python 3 用于服务端集成测试。
ACL 可在其源码目录执行 make 和 make packinstall 安装;系统目录安装可能需要管理员权限。其他依赖可使用已安装的开发包,或按上游构建说明安装到自定义前缀,并通过 CMAKE_PREFIX_PATH 指定。
xxHash 也可直接使用本地源码,不需要全局安装:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \
-DPKV_XXHASH_SOURCE_DIR=/path/to/xxHash
cmake --build build -j 4若依赖已安装,直接运行 make。本地路径也可写入 Git 忽略的 Makefile.local:
CMAKE_ARGS += -DPKV_XXHASH_SOURCE_DIR="/path/to/xxHash"键值存储和复制使用原生二进制记录。请使用新库或已有原生记录的库,旧 JSON 键值和旧版复制兼容转换已移除。
构建产物是 build/pkv,源码目录不生成可执行文件。xxHash 源码模式使用私有命名空间,不修改其源码目录。项目同时包含 LGPL-2.1 许可证和单独许可的 fpconv。
已有与当前源码和 Clang 工具链匹配的 .profdata 时,可用独立目录构建 PGO 版本。
make BUILD_DIR=build-pgo PKV_PGO_PROFILE=/path/to/pkv.profdata在仓库根目录运行:
./build/pkv alone mdb.cf示例配置的客户端端口是 19001,使用内存后端,不会在重启后保留数据。另开终端连接:
$ redis-cli -p 19001
127.0.0.1:19001> PING
PONG
127.0.0.1:19001> SET greeting "Hello, PKV" EX 60
OK
127.0.0.1:19001> GET greeting
"Hello, PKV"
127.0.0.1:19001> HSET user:1 name Alice language zh-CN
(integer) 2
127.0.0.1:19001> LPUSH jobs task:1 task:2
(integer) 2
127.0.0.1:19001> ZADD ranking 100 Alice 90 Bob
(integer) 2连接级数据库选择和事务示例(同一连接执行):
SELECT 1
MULTI
SET visits 0
INCR visits
GET visits
EXEC
EXEC 返回三个结果:OK、1、"1"。客户端版本不同,输出排版可能略有差异。
可选引擎默认关闭,须先安装开发依赖,再显式启用:
make HAS_ROCKSDB=YES # RocksDB
make HAS_WT=YES # WiredTiger
make HAS_TBB=YES # oneTBB
# 可组合启用;其他选项:HAS_JEMALLOC=YES、BUILD_WITH_C11=YES| 后端 | 启动配置 | 原生五类型页事务 | 持久化与边界 |
|---|---|---|---|
mdb |
mdb.cf |
支持 | 默认构建;进程内存 |
mdb_tbb |
mdb_tbb.cf |
支持 | 可选 oneTBB;保留命令键锁,并非全路径无锁 |
rdb |
rdb_native.cf |
单物理实例支持 | 原子 WriteBatch;普通写默认不启用 fsync |
wdb |
wdb_native.cf |
单物理实例支持 | 快照事务与同步日志 |
mdb_htable / mdb_avl |
同名 .cf |
不支持原生集合页事务 | 旧引擎路径;Hash/List/Set/ZSet 请求显式拒绝 |
例如:./build/pkv alone rdb_native.cf。原生磁盘示例使用独立新目录;旧的 rdb.cf / wdb.cf 包含多个物理路径,不会自动合并或迁移。跨独立物理存储的原子变更仍受限制。详见 RocksDB、WiredTiger 和 oneTBB。
原生页属于逻辑键,不占用用户键名,也不出现在 SCAN 结果中。String 的小值最多内联 1024 字节;较大值使用 16 KiB 分块。List 使用双端页链,Hash/Set 使用有界 AVL 节点与片段,ZSet 在同一页族中维护成员索引和分数索引。页大小有界不代表整个命令、结果集或事务的内存恒定。
旧 JSON 记录通过 codec 兼容层读取,在适用的类型访问或变更路径上原子迁移并保留绝对过期时间;MGET 保持只读。升级和降级须遵守格式文档,没有自动降级工具。
修改所选 .cf 的 service pkv { ... } 配置块;以下为关键字段说明,并非完整配置:
| 参数 | 含义 |
|---|---|
master_service |
ACL 客户端监听地址,示例 127.0.0.1|19001 |
service |
PKV 服务地址标识,默认 127.0.0.1:19001;修改端口时与监听配置保持一致,RPC 端口由此加 10000 |
fiber_threads |
ACL 工作线程数;以所选配置文件为准 |
dbtype / dbpath |
后端及存储路径;多路径不等同于一个原子提交域 |
databases |
逻辑库数量,默认 16;SELECT 按连接选择 |
db_count |
每个内存逻辑库的物理分片数,默认 256,与逻辑库数量独立 |
active_expire |
主动过期,默认启用;批次与间隔可配置 |
requirepass / aclfile |
前端默认用户密码或 ACL 用户文件 |
replica_rpc_source |
可选上游 RPC 地址,例如 127.0.0.1:29001;不是 Redis 客户端端口 |
replica_read_only |
配置实时接收端后默认拒绝客户端写入 |
move_journal_path |
默认 auto:原生磁盘池绑定 MOVE 决策日志;内存后端不创建日志 |
前端 ACL 与 RPC 启动密码策略分别处理,详见认证。已绑定的磁盘 MOVE 域必须保留根路径、逻辑库数量、标记与日志身份,不能随意关闭日志,见启动恢复。
- Redis 兼容仍在进行。 当前命令族覆盖见兼容性文档和
COMMAND/COMMAND INFO;不承诺完整选项、复杂度或性能等同于 Redis。脚本、Streams、Redis RDB/AOF 等仍未完成。 - EXEC 隔离与崩溃原子性有区别。 满足条件的单逻辑库、单提交域原生事务一次提交;跨库、多物理存储及部分旧路径仍可能在崩溃后保留成功前缀。运行时命令错误不会回滚此前成功命令。
- 复制是私有实时流。 尚无全量同步、断线补齐、Redis PSYNC 或自动故障切换。已有数据不能仅靠订阅流初始化;磁盘接收端尚不支持含 MOVE 的混合组持久恢复。
- 集群功能尚不完整。 已有槽位路由与检查,但迁移、ASK 和自动故障切换未完成;集群模式限 DB 0。本地 Pub/Sub 不提供跨节点广播。
- 持久化取决于引擎策略。 单次磁盘 MOVE 有独立决策日志与启动重放;这不是整个 EXEC 的跨库恢复保证。进程中断测试不等同于断电安全验证。
ctest --test-dir build --output-on-failure完整服务测试需要 Python 3 及创建临时回环 TCP 监听的权限;可选后端测试取决于构建开关。独立协议测试、ASan/UBSan 和参考服务对比方法见测试指南。本次文档不把历史测试数量当作当前全量验证结果。
仓库保留了 String 存储微基准、EXEC 工作区开销、命令分发测量和过期索引测量。这些结果各有负载、平台与版本范围,不构成对官方 Redis 的整体性能优势结论。
性能进度记录当前数据及历史实验。变更型命令基线给出 24 个写入场景的 P1/P64、延迟与内存。累计有 126/188 条注册顶层命令具备命名性能场景。位图单页复制专项记录等值 SETBIT、BITOP 与混合写入内存。密集 PFMERGE 写回的单工作线程 P64 等值写入在独立长测中达到隔离 Redis 的约 91%。
Set 与 ZSet 运算矩阵覆盖交并差集、基数查询、结果存储和范围删除,包含三阶段内存和本机压测客户端的 Pipeline 计数诊断。
紧凑 ZSet 单成员弹出给出 MDB、oneTBB 与 Redis 的 P1/P64、四工作线程和写后内存对照。单工作线程 P64 顺序 32 成员 ZPOPMAX 的 MDB 吞吐为 Redis 的约 53%。
分页 ZSet 批量弹出覆盖 ZPOPMAX、ZMPOP 和超长成员回退。192 成员形态每键弹出 96 个后,MDB 的堆增量约为父版的 27%。
同一父版上的扩展 100 场景对照和默认 21 场景对照合计覆盖 188 条注册顶层命令中的 85 条,另有上方的 PFMERGE 专项。22 种形态的逐类型内存与 List 专项保留 LPUSH/RPUSH、GET 对照和内存数据。其余命令、各命令选项及大集合内存仍需验证和优化。 历史 C41 的MDB分页目录实验保留内存收益与GET回退记录;C42 小型记录桶原型因大键空间GET回退已撤回。C39 的Hash查找与 C40 的List已知TTL提交亦保留各自测量范围。上述 C32 表是历史已验收版本,C46仍是局部实验性改进。 历史 C43 的List整数写入实验及构建审计因端到端收益不足已撤回:指令数减少并未解决List管线差距,最终源码、目标文件和程序均恢复至C41基线。 新增 oneTBB 分片内存及 P1/P64/P1024 专项:内存收益与吞吐回退并存,默认分片数暂未调整。 后续扫描索引压缩实验因吞吐负样本已撤回。
先阅读软件架构和文档导航,再根据修改范围运行相关 CTest。提交变更时说明后端、构建模式、行为变化及验证范围;涉及存储格式、复制或恢复时,同时更新边界与迁移说明。
最近的小元素 List 填充实验保留全部 720 项时序和内存负样本,两个候选均已撤回。
已保留紧凑 List 分流的回调借用修复,默认 P64 四项 List 吞吐提高约 12%–16%;P1 负样本和内存范围见报告,整体目标仍未完成。
List读取客户端控制对照记录同版本波动、旧/新复核及当前RPUSH采样;默认21项全表仍见上文。
2026-11-08 请求对象回收候选撤回:72项P64与完整证据
2026-11-08 List缓存候选撤回:108项P1/P64与内存观测
2026-11-08 List检查器候选撤回:216项P1/P64及分配证据
2026-11-08 LRANGE结果复用候选撤回:162项对照与分配证据
2026-11-08 LRANGE整帧候选撤回:1428项最终对照、混合短值与恢复记录
2026-11-08 按页RESP分块原型:216项编码微测,尚未接入服务端
2026-11-08 分段LRANGE集成候选撤回:240项DAO、108项P1/P64与恢复证据
2026-11-08 Hash表示边界:96项内存、288项P1/P64与实际页面结构
2026-11-08 保留紧凑Hash等长覆盖:144项DAO、804项网络与全部复核
2026-11-08 历史C31默认21项P1/P64及p99:378项对照,保留全部负样本
2026-11-08 保留Hash同步回调引用:360项DAO、1104项网络,含默认、多线程与控制项代价
2026-11-08 单根512字段Hash实验否决:720项DAO,空间收益与点操作回退