KVstore 是一个使用 C 语言实现的高性能内存型 Key-Value 存储服务。项目从底层网络模型、协议解析、存储引擎抽象到客户端测试工具均为手写实现,适合作为 Linux 网络编程、数据结构工程化、异步 I/O 模型和服务端架构设计的综合实践项目。
项目当前支持 SET、GET、DEL、MOD、EXIST 五类基础命令,服务端通过 TCP 文本协议对外提供访问能力。内部将网络层、协议层和存储层解耦,同一套 KV 协议可以运行在 epoll reactor、io_uring proactor 和 NtyCo coroutine 三种网络模型之上;存储层也可以在数组、哈希表、红黑树、跳表之间切换。
- 多网络模型支持:内置
epollReactor、io_uringProactor、NtyCo协程网络层,便于对比不同 Linux I/O 编程模型。 - 可插拔存储引擎:通过统一
kvs_ops_t操作表屏蔽底层实现差异,协议层无需关心具体数据结构。 - 多种核心数据结构:已实现顺序数组、拉链哈希表、红黑树、跳表四类 KV 引擎。
- 清晰的协议分层:网络层只负责收发字节流,协议层负责命令解析和响应生成,存储层负责键值数据管理。
- 内置回归测试客户端:提供基础功能测试、高频循环测试和多 key 批量读写测试。
- 多语言客户端示例:包含 Python、Go、JavaScript、Rust、Java 示例,方便快速验证跨语言访问。
- 适合继续演进:项目结构适合扩展 TTL、持久化、线程池、多 Reactor、RESP 协议、AOF/RDB、benchmark 等能力。
flowchart LR
Client[Client / testcase / nc] --> TCP[TCP Server]
subgraph Network[Network Layer]
Reactor[epoll Reactor]
Proactor[io_uring Proactor]
Coroutine[NtyCo Coroutine]
end
TCP --> Reactor
TCP --> Proactor
TCP --> Coroutine
Reactor --> Protocol[KV Protocol]
Proactor --> Protocol
Coroutine --> Protocol
Protocol --> Engine[kvs_engine_t]
subgraph Storage[Storage Engines]
Array[Array]
Hash[Hash Table]
RBTree[Red-Black Tree]
Skiplist[Skip Table]
end
Engine --> Array
Engine --> Hash
Engine --> RBTree
Engine --> Skiplist
核心调用链如下:
socket/epoll/io_uring/coroutine
|
v
kvs_protocol()
|
v
kvs_filter_protocol()
|
v
g_engine.ops.set/get/del/mod/exist()
|
v
array / hash / rbtree / skiptable
KVstore
├── CMakeLists.txt # CMake 构建入口
├── include
│ ├── kvstore.h # 全局配置、协议/引擎抽象、网络入口声明
│ ├── server.h # Reactor 连接结构与服务端配置
│ ├── kvs_array.h # 数组引擎接口
│ ├── kvs_hash.h # 哈希表引擎接口
│ ├── kvs_rbtree.h # 红黑树引擎接口
│ └── kvs_skiptable.h # 跳表引擎接口
├── src
│ ├── kvstore.c # main、协议解析、引擎注册
│ ├── reactor.c # epoll Reactor 网络层
│ ├── proactor.c # io_uring Proactor 网络层
│ ├── ntyco_server.c # NtyCo 协程网络层
│ ├── kvs_array.c # 顺序数组存储引擎
│ ├── kvs_hash.c # 哈希表存储引擎
│ ├── kvs_rbtree.c # 红黑树存储引擎
│ ├── kvs_skiptable.c # 跳表存储引擎
│ └── testcase.c # TCP 自动化测试客户端
├── kvs-client # 多语言客户端示例
└── third_party
└── README.md # NtyCo 依赖获取说明
以 Ubuntu / Debian 为例:
sudo apt update
sudo apt install -y build-essential cmake ninja-build liburing-dev项目的协程网络层依赖 NtyCo,由于第三方源码通常不直接提交到本仓库,请在 third_party 目录下拉取并编译:
cd third_party
git clone https://github.com/wangbojing/NtyCo.git
cd NtyCo
make编译完成后,应能看到:
third_party/NtyCo/libntyco.a
third_party/NtyCo/core/nty_coroutine.h
回到项目根目录:
cmake -S . -B build -G Ninja
cmake --build build构建完成后会生成两个可执行文件:
build/kvstore # KV 存储服务端
build/kvstore_test # 自动化测试客户端
如果你没有安装 Ninja,也可以使用 Makefile 生成器:
cmake -S . -B build
cmake --build build./build/kvstore 2000服务端会监听 0.0.0.0:2000。
另开一个终端:
printf "SET name kvstore\r\n" | nc 127.0.0.1 2000
printf "GET name\r\n" | nc 127.0.0.1 2000
printf "MOD name redis\r\n" | nc 127.0.0.1 2000
printf "EXIST name\r\n" | nc 127.0.0.1 2000
printf "DEL name\r\n" | nc 127.0.0.1 2000也可以进入交互模式:
nc 127.0.0.1 2000然后输入:
SET Teacher King
GET Teacher
MOD Teacher Darren
EXIST Teacher
DEL Teacher
KVstore 当前使用简单的 TCP 文本协议,命令和参数之间使用空白字符分隔,服务端响应以 \r\n 结尾。
| 命令 | 格式 | 成功响应 | 说明 |
|---|---|---|---|
SET |
SET key value |
OK |
新增键值对;如果 key 已存在,返回 EXIST |
GET |
GET key |
value |
获取 key 对应的 value;不存在返回 NO EXIST |
DEL |
DEL key |
OK |
删除 key;不存在返回 NO EXIST |
MOD |
MOD key value |
OK |
修改已存在 key 的 value;不存在返回 NO EXIST |
EXIST |
EXIST key |
EXIST |
判断 key 是否存在;不存在返回 NO EXIST |
错误命令或参数数量不正确时,服务端返回:
ERROR
启动服务端后,使用内置测试客户端进行验证:
./build/kvstore_test 127.0.0.1 2000 0测试模式说明:
| 模式 | 命令 | 说明 |
|---|---|---|
0 |
./build/kvstore_test 127.0.0.1 2000 0 |
基础功能回归测试 |
1 |
./build/kvstore_test 127.0.0.1 2000 1 |
单 key 高频循环测试 |
2 |
./build/kvstore_test 127.0.0.1 2000 2 |
多 key 批量读写测试 |
成功时会看到类似输出:
==> PASS -> SET-Teacher
==> PASS -> GET-Teacher
==> PASS -> MOD-Teacher
模式 1 和模式 2 会输出耗时与粗略 QPS,便于观察不同存储引擎和网络模型下的性能差异。
网络模型在 include/kvstore.h 中通过宏选择:
#define NETWORK_REACTOR 0
#define NETWORK_PROACTOR 1
#define NETWORK_NTYCO 2
#define NETWORK_SELECT NETWORK_REACTOR可选项:
| 网络模型 | 宏 | 实现文件 | 说明 |
|---|---|---|---|
| Reactor | NETWORK_REACTOR |
src/reactor.c |
基于 epoll 的事件驱动模型 |
| Proactor | NETWORK_PROACTOR |
src/proactor.c |
基于 io_uring 的异步完成事件模型 |
| Coroutine | NETWORK_NTYCO |
src/ntyco_server.c |
基于 NtyCo 的协程式网络模型 |
修改宏后重新构建:
cmake --build build存储引擎同样在 include/kvstore.h 中通过宏选择:
#define ENABLE_ARRAY 0
#define ENABLE_HASH 0
#define ENABLE_RBTREE 0
#define ENABLE_SKIPTABLE 1当前默认启用跳表。切换时请保证同一时间只启用一个引擎:
| 引擎 | 宏 | 实现文件 | 特点 |
|---|---|---|---|
| Array | ENABLE_ARRAY |
src/kvs_array.c |
实现最直观,适合理解协议和引擎抽象 |
| Hash Table | ENABLE_HASH |
src/kvs_hash.c |
拉链法处理冲突,平均查找效率较高 |
| Red-Black Tree | ENABLE_RBTREE |
src/kvs_rbtree.c |
自平衡二叉搜索树,适合有序 key 场景 |
| Skip Table | ENABLE_SKIPTABLE |
src/kvs_skiptable.c |
概率平衡结构,查找、插入、删除期望复杂度优秀 |
协议层通过统一操作表访问存储引擎:
typedef struct kvs_ops_s {
int (*create)(void* engine);
void (*destroy)(void* engine);
int (*set)(void* engine, char* key, char* value);
char* (*get)(void* engine, char* key);
int (*del)(void* engine, char* key);
int (*mod)(void* engine, char* key, char* value);
int (*exist)(void* engine, char* key);
} kvs_ops_t;这个设计让新增存储引擎变得非常直接:实现同样的一组接口,并在 init_kvengine() 中注册即可。
kvs-client 目录提供了多语言 TCP 客户端示例:
kvs-client
├── go-kvstore.go
├── javakvstore.java
├── js-kvstore.js
├── py-kvstore.py
└── rust-kvstore.rs
这些客户端主要用于演示跨语言访问方式。运行前请根据你的服务端地址调整示例中的 IP 和端口。
Python 示例:
python3 kvs-client/py-kvstore.pyGo 示例:
go run kvs-client/go-kvstore.go三种网络层都只保存一个业务处理函数:
typedef int (*msg_handler)(char *msg, int length, char *response);当网络层收到完整请求后,将请求内容交给 kvs_protocol(),并把协议层生成的响应发回客户端。这样网络模型可以独立替换,而不会影响协议解析和存储逻辑。
kvs_protocol() 负责拆分 token,kvs_filter_protocol() 根据命令类型调用当前引擎的对应操作:
SET -> g_engine.ops.set()
GET -> g_engine.ops.get()
DEL -> g_engine.ops.del()
MOD -> g_engine.ops.mod()
EXIST -> g_engine.ops.exist()
g_engine 保存当前启用的引擎实例和操作表。无论底层是数组、哈希表、红黑树还是跳表,对上层来说都是同一套 KV 操作接口。
项目通过 kvs_malloc() 和 kvs_free() 统一包装内存申请与释放。当前实现基于 malloc/free,后续可以替换为内存池、对象池或更细粒度的统计调试器。
- 基础 TCP KV 服务端
-
SET / GET / DEL / MOD / EXIST文本协议 -
epollReactor 网络模型 -
io_uringProactor 网络模型 - NtyCo 协程网络模型
- 数组、哈希表、红黑树、跳表存储引擎
- 自动化测试客户端
- 多语言客户端示例
- 更完善的命令协议,例如 RESP 兼容模式
- TTL 过期机制
- AOF / Snapshot 持久化
- 多线程 Reactor 或线程池模型
- Benchmark 工具与性能报告
- 更完整的错误码与日志系统
- CI 自动构建与测试
- Linux TCP socket 编程
epoll事件驱动模型io_uring异步 I/O 编程- 协程式服务端编程
- Reactor / Proactor 架构差异
- 哈希表、红黑树、跳表的工程实现
- C 项目模块化设计
- CMake 多目标构建
- 网络协议解析与测试客户端设计
- 当前项目是内存型 KV 存储,进程退出后数据不会持久化。
- 当前协议以空白字符拆分 token,因此 value 暂不支持包含空格。
- 默认构建会链接
liburing和third_party/NtyCo/libntyco.a,即使当前选择的是 Reactor 网络模型,也需要提前准备相关依赖。 - 当前服务端以单进程方式运行,适合作为网络模型和存储引擎实验平台;生产级能力还需要补充持久化、并发安全、限流、日志、监控、压测和故障恢复等模块。
本项目基于 MIT License 开源,你可以自由学习、使用、修改和分发本项目代码。