Skip to content

songs66/KVstore

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

KVstore

Language Build Platform Network

KVstore 是一个使用 C 语言实现的高性能内存型 Key-Value 存储服务。项目从底层网络模型、协议解析、存储引擎抽象到客户端测试工具均为手写实现,适合作为 Linux 网络编程、数据结构工程化、异步 I/O 模型和服务端架构设计的综合实践项目。

项目当前支持 SETGETDELMODEXIST 五类基础命令,服务端通过 TCP 文本协议对外提供访问能力。内部将网络层、协议层和存储层解耦,同一套 KV 协议可以运行在 epoll reactorio_uring proactorNtyCo coroutine 三种网络模型之上;存储层也可以在数组、哈希表、红黑树、跳表之间切换。

项目亮点

  • 多网络模型支持:内置 epoll Reactor、io_uring Proactor、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
Loading

核心调用链如下:

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 依赖获取说明

快速开始

1. 安装依赖

以 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

2. 构建项目

回到项目根目录:

cmake -S . -B build -G Ninja
cmake --build build

构建完成后会生成两个可执行文件:

build/kvstore        # KV 存储服务端
build/kvstore_test   # 自动化测试客户端

如果你没有安装 Ninja,也可以使用 Makefile 生成器:

cmake -S . -B build
cmake --build build

3. 启动服务端

./build/kvstore 2000

服务端会监听 0.0.0.0:2000

4. 使用 nc 访问

另开一个终端:

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.py

Go 示例:

go run kvs-client/go-kvstore.go

设计细节

1. 网络层与业务层解耦

三种网络层都只保存一个业务处理函数:

typedef int (*msg_handler)(char *msg, int length, char *response);

当网络层收到完整请求后,将请求内容交给 kvs_protocol(),并把协议层生成的响应发回客户端。这样网络模型可以独立替换,而不会影响协议解析和存储逻辑。

2. 协议层统一分发

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()

3. 存储引擎统一抽象

g_engine 保存当前启用的引擎实例和操作表。无论底层是数组、哈希表、红黑树还是跳表,对上层来说都是同一套 KV 操作接口。

4. 内存分配入口统一

项目通过 kvs_malloc()kvs_free() 统一包装内存申请与释放。当前实现基于 malloc/free,后续可以替换为内存池、对象池或更细粒度的统计调试器。

开发路线图

  • 基础 TCP KV 服务端
  • SET / GET / DEL / MOD / EXIST 文本协议
  • epoll Reactor 网络模型
  • io_uring Proactor 网络模型
  • NtyCo 协程网络模型
  • 数组、哈希表、红黑树、跳表存储引擎
  • 自动化测试客户端
  • 多语言客户端示例
  • 更完善的命令协议,例如 RESP 兼容模式
  • TTL 过期机制
  • AOF / Snapshot 持久化
  • 多线程 Reactor 或线程池模型
  • Benchmark 工具与性能报告
  • 更完整的错误码与日志系统
  • CI 自动构建与测试

适合学习的主题

  • Linux TCP socket 编程
  • epoll 事件驱动模型
  • io_uring 异步 I/O 编程
  • 协程式服务端编程
  • Reactor / Proactor 架构差异
  • 哈希表、红黑树、跳表的工程实现
  • C 项目模块化设计
  • CMake 多目标构建
  • 网络协议解析与测试客户端设计

注意事项

  • 当前项目是内存型 KV 存储,进程退出后数据不会持久化。
  • 当前协议以空白字符拆分 token,因此 value 暂不支持包含空格。
  • 默认构建会链接 liburingthird_party/NtyCo/libntyco.a,即使当前选择的是 Reactor 网络模型,也需要提前准备相关依赖。
  • 当前服务端以单进程方式运行,适合作为网络模型和存储引擎实验平台;生产级能力还需要补充持久化、并发安全、限流、日志、监控、压测和故障恢复等模块。

License

本项目基于 MIT License 开源,你可以自由学习、使用、修改和分发本项目代码。

About

A high-performance in-memory KV store in C with epoll, io_uring, coroutine networking, and pluggable storage engines.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors