Skip to content

Repository files navigation

Store System

版本: 0.1.11

一个高性能的嵌入式键值存储系统,基于 bbolt (jammdb) + SQLite 双存储引擎,提供 gRPC 和 RESTful 双接口,支持写合并优化、WAL 原子写入、副本故障转移、进程守护自愈和大 Value(最大 100MB)读写。

特性

  • 双存储引擎:jammdb (B+树 KV) + SQLite (元数据,WAL 模式)
  • 双接口:gRPC (tonic) + RESTful (warp)
  • 写合并优化:put 先入内存缓冲,后台批量 fsync,写入延迟 < 1ms
  • WAL 原子写入:Write-Ahead Log 三步协议 (WAL→KV→Meta),崩溃恢复零数据丢失
  • 副本故障转移:Rendezvous Hashing 路由 + 同步写主副本 + 异步写备副本,Worker 宕机自动 fallback
  • Master Pending 缓存:区域 Worker 宕机时 Master 本地持久化接盘,Worker 恢复后自动写回
  • 进程守护自愈:store_guardian 独立进程,深度探针检测假死,指数退避自动重启
  • 大 Value 支持:gRPC 消息上限 256MB,实测支持 100MB 单条读写
  • LRU 读缓存:moka 自动淘汰,无需手动管理容量
  • 批量事务:元数据批量写入用真正的单事务提交 (put_batch_txn)
  • 零拷贝优化:gRPC 读取直接传递 protobuf bytes,避免字节拷贝
  • 多节点集群:Master-Worker 架构,支持动态注册/心跳/故障检测
  • QuadKey 区域路由:按 quadkey[0] 将数据分流到 4 个区域 Worker,互不交叉
  • QuadKey 分片存储:level≤8→base, 8<level<18→4位前缀, level≥18→8位前缀
  • Epoch 桶隔离:不同 epoch 版本数据目录隔离,支持全量快照式数据管理
  • 动态数据类型路由:RESTful /{data_type}/{key} 替代硬编码 /objects/
  • Master 统一配置:kv_name/kv_ext/cache_size 等由 Master 统一下发 Worker
  • 分片存储:ShardManager 支持数据分片,独立 WAL 恢复
  • 健康监控:CPU/内存/磁盘使用率实时采集,心跳上报
  • 日志采集:Worker 日志通过 WebSocket 推送至 Master,SQLite 持久化

目录结构

StoreSystem/
├── Cargo.toml              # 服务器端依赖配置
├── build.rs                # protobuf 编译脚本
├── master.yaml             # Master 节点配置(配置统一管理中心)
├── worker-0.yaml           # Worker-0 极简启动配置
├── worker-1.yaml           # Worker-1 极简启动配置
├── worker-2.yaml           # Worker-2 极简启动配置
├── worker-3.yaml           # Worker-3 极简启动配置
├── proto/
│   └── store.proto         # gRPC 服务定义 (3 个 service)
├── src/
│   ├── main.rs             # 程序入口 (master/worker/standalone 模式)
│   ├── lib.rs              # 库入口,模块声明
│   ├── config.rs           # YAML 配置加载
│   ├── store.rs            # 核心存储层 (写合并 + LRU 缓存 + WAL 刷盘)
│   ├── kv.rs               # jammdb KV 存储封装
│   ├── meta.rs             # SQLite 元数据 (含 WAL 表 + 批量事务)
│   ├── shard.rs            # 分片管理器 (ShardManager + ShardStrategy)
│   ├── grpc.rs             # gRPC 服务实现 (StoreService)
│   ├── http.rs             # RESTful 服务实现
│   ├── master.rs           # Master 节点 (路由 + 副本 + 心跳)
│   ├── master_store.rs     # Master 集群元数据库
│   ├── master_admin_http.rs # Master 管理 API (集群概览/日志/Worker 列表)
│   ├── master_http.rs      # Master HTTP 客户端
│   ├── master_ws.rs        # Master WebSocket 客户端
│   ├── master_log_ws.rs    # Master 日志 WebSocket 服务端
│   ├── worker.rs           # Worker 节点 (存储 + WAL 恢复 + 心跳)
│   ├── worker_http.rs      # Worker RESTful API
│   ├── worker_ws.rs        # Worker WebSocket 服务端
│   ├── logger.rs           # 日志采集与持久化 (WorkerLogger + LogStore)
│   ├── health.rs           # 系统健康监控 (CPU/内存/磁盘)
│   └── error.rs            # 错误类型定义
├── client/                 # 性能测试客户端(独立项目)
│   ├── Cargo.toml
│   ├── build.rs
│   └── src/
│       ├── main.rs         # 测试主程序(多场景性能测试)
│       ├── bin/
│       │   └── fault_test.rs # 副本故障恢复测试
│       ├── grpc_client.rs  # gRPC 客户端
│       └── restful_client.rs # RESTful 客户端
├── guardian/               # 进程守护者(独立项目)
│   ├── Cargo.toml
│   ├── build.rs
│   ├── proto/
│   │   └── store.proto
│   └── src/
│       ├── main.rs         # CLI 入口 + 监控循环
│       ├── config.rs       # GuardianConfig 配置解析
│       ├── process.rs      # 进程状态机 + spawn/kill
│       ├── prober.rs       # 深度探针(gRPC Put+Get)
│       └── policy.rs       # 重启退避+冷却策略
├── guardian.yaml            # 进程守护者配置
└── admin-ui/               # Next.js 管理界面 (端口 3000)

快速开始

环境要求

  • Rust 1.84+ (stable)
  • macOS / Linux

编译

# 编译全部(server + client + guardian)
make build

# 或单独编译
cargo build --release                    # server
cargo build --release -p store_client    # client
cargo build --release -p store_guardian  # guardian

单机模式启动

# 单机模式使用 master.yaml(standalone 段使用默认值)
./target/release/store_system --config master.yaml standalone
  • gRPC 服务:http://0.0.0.0:50051
  • RESTful 服务:http://0.0.0.0:8080
  • 数据目录:data/(自动创建)

集群模式启动(QuadKey 4 区域)

# 终端 1: 启动 Master
./target/release/store_system --config master.yaml

# 终端 2-5: 启动 4 个区域 Worker
./target/release/store_system --config worker-0.yaml
./target/release/store_system --config worker-1.yaml
./target/release/store_system --config worker-2.yaml
./target/release/store_system --config worker-3.yaml

集群启动后端口分布:

节点 region gRPC RESTful 负责数据
Master 50051 路由分流
Worker-0 0 50161 52161 quadkey 0xxx
Worker-1 1 50162 52162 quadkey 1xxx
Worker-2 2 50163 52163 quadkey 2xxx
Worker-3 3 50164 52164 quadkey 3xxx

进程守护启动(自动拉起 + 假死检测)

# 通过 store_guardian 启动并守护全部进程
./target/release/store_guardian --config guardian.yaml

# 仅守护 Master
./target/release/store_guardian --config guardian.yaml --role master

# 仅守护 Worker
./target/release/store_guardian --config guardian.yaml --role worker

守护进程会自动:

  • depends_on 顺序启动所有进程
  • 每 5s 执行深度探针(gRPC Put+Get 往返)
  • 连续 3 次探针失败 → kill -9 + 重启(指数退避 1s→2s→4s→...→60s)
  • 连续 10 次重启失败 → 进入冷却 300s,防止重启风暴

运行性能测试

cd client
./target/release/store_client

运行故障恢复测试

cd client
cargo build --release --bin fault_test
# 确保 Master + 2 Worker 已启动
../target/release/fault_test

API 参考

gRPC 接口

定义于 proto/store.proto

方法 请求 响应 说明
Put PutRequest{key, value, content_type, tags, epoch, quadkey?, level?} PutResponse{meta} epoch 指定版本桶,quadkey非空→区域路由,空→哈希路由
Get GetRequest{key, epoch, quadkey?, level?} GetResponse{value, meta} 同上
Delete DeleteRequest{key, epoch, quadkey?, level?} DeleteResponse{success} 同上
Exists ExistsRequest{key, epoch, quadkey?, level?} ExistsResponse{exists} 同上
List ListRequest{prefix, limit, epoch, quadkey?, level?} ListResponse{metas} 同上
PutBatch PutBatchRequest{items[]} PutBatchResponse{metas[]} items[] 每条含 epoch, quadkey, level

Master 管理接口 (gRPC)

方法 说明
RegisterWorker Worker 注册到集群
Heartbeat Worker 心跳上报 (含健康 + 写入统计)
ListWorkers 获取所有 Worker 列表
GetRoute 查询 key 的路由目标

RESTful 接口

路径模板:/{data_type}/{key}?quadkey=&level=...

方法 路径 说明
POST /{type}/{key}?quadkey=&level=&content_type=... 写入,quadkey可选
GET /{type}/{key}?quadkey=&level= 读取
DELETE /{type}/{key}?quadkey=&level= 删除
GET /{type}?prefix=&limit=&quadkey=&level= 列表
POST /{type}/batch 批量写入

Master Admin API (RESTful)

方法 路径 说明
GET /api/v1/overview 集群概览
GET /api/v1/workers Worker 列表
GET /api/v1/workers/:id Worker 详情
GET /api/v1/logs?level=...&worker_id=... 日志查询
GET /api/v1/logs/stats 日志统计
POST /api/v1/logs/:id/ack 标记日志已读
GET /api/v1/routes 路由规则
GET /api/v1/health 健康检查
WS /api/v1/ws/logs 实时日志流

架构设计

写合并(Write Coalescing)

核心优化,将同步 fsync 转为异步批量刷盘:

优化前(每次 put):
  put → jammdb 开事务 → 写 → commit(fsync) → SQLite INSERT → 返回
  延迟:300ms+(两次 fsync)

优化后(每次 put):
  put → 写内存 pending + 缓存 → 立即返回 (<1ms)

后台刷盘任务(每 5ms)+ WAL 原子保证:
  ① 写 WAL 意图记录 → ② jammdb 批量写(1次fsync) → ③ SQLite 批量INSERT + 原子清除WAL

代价:崩溃时 WAL 中的记录会在下次启动时自动恢复,数据零丢失。

WAL 三步协议

客户端                    Worker
  │                          │
  │  put(key, value)         │
  │─────────────────────────→│  ① 写入 WriteBuffer(pending) + 返回
  │                          │
  │   后台 flusher 触发       │
  │                          │  ② 写 WAL (write_intent_wal 表)
  │                          │  ③ 写 KV (jammdb 单事务)
  │                          │  ④ 写 Meta + 原子清除 WAL
  │                          │
  │      崩溃恢复             │
  │                          │  扫描 write_intent_wal
  │                          │  ├─ KV 有数据 → 补写 Meta
  │                          │  └─ KV 无数据 → 丢弃 WAL 记录

副本写入 + 故障转移

                 Master
                   │
    Rendezvous Hashing 路由
    ┌──────────────────┴──────────────────┐
    │                                     │
    ▼                                     ▼
Worker-1 (主副本)                    Worker-2 (备副本)
    │ sync put                           async put
    │                                     │
    │←── 主副本成功 ──→ 返回 Client       │ (失败不影响主流程)
    │                                     │
    │   若主副本不可达:
    │       fallback → Worker-2 同步写入
    │       同时异步尝试 Worker-1

存储分层

┌─────────────────────────────────────────────────┐
│              gRPC (tonic) + RESTful (warp)       │
│                      ↓                          │
│              Master (quadkey[0]区域路由)         │
│    ┌──────┬──────┬──────┬──────┐                │
│    ▼      ▼      ▼      ▼                      │
│    W-0   W-1   W-2   W-3   (4 区域 Worker)     │
│  region0 region1 region2 region3                │
│    │      │      │      │                       │
│ 0xxx   1xxx   2xxx   3xxx  (quadkey分区)        │
│  ┌────────────────────────────┐                 │
│  │  LRU + WriteBuffer + WAL   │                 │
│  │  KvStore + MetaStore       │                 │
│  └────────────────────────────┘                 │
└─────────────────────────────────────────────────┘

QuadKey 分片路径规则

层级 DB 名 路径示例
≤ 8 base {dir}/{type}/base.kv
9-17 quadkey[..4] {dir}/{type}/12/3021.kv
≥ 18 quadkey[..8] {dir}/{type}/20/30211234.kv

v0.1.10 性能指标

测试环境

项目 配置
操作系统 Linux
Rust 版本 1.96+
CPU x86_64
测试日期 2026-06-21
集群 Master + 4 Workers (QuadKey区域)

完整性能测试报告

                              存储系统性能测试报告
测试项                                              次数     平均延迟(ms)      总耗时(ms)        ops/s         MB/s
----------------------------------------------------------------------------------------------------------
gRPC 单次写入 (1KB)                                  20        0.484        9.759       2049.4          2.0
gRPC 单次写入 (1MB)                                  10        6.442       72.177        138.5        138.5
gRPC 单次写入 (10MB)                                  5      120.803      642.216          7.8         77.9
gRPC 单次写入 (50MB)                                  3      469.939     1551.186          1.9         96.7
gRPC 单次写入 (100MB)                                 2     1024.315     2258.421          0.9         88.6
gRPC 单次读取 (1KB)                                  20        2.564       51.287        390.0          0.4
gRPC 单次读取 (1MB)                                  10        6.576       65.755        152.1        152.1
gRPC 单次读取 (10MB)                                  5       62.251      311.256         16.1        160.6
gRPC 单次读取 (50MB)                                  3      737.287     2211.860          1.4         67.8
gRPC 单次读取 (100MB)                                 2     2326.428     4652.855          0.4         43.0
gRPC 批量写入 (1MB x 10条/批)                           5       55.363      285.838         17.5        174.9
gRPC 批量写入 (10MB x 5条/批)                           3      431.536     1386.104          2.2        108.2
gRPC 并发写入 (1MB x 10并发)                           20       52.265      228.563         87.5         87.5
gRPC 并发写入 (10MB x 5并发)                           10      218.866      549.959         18.2        181.8
RESTful 单次写入 (1KB)                               20        0.222        4.480       4464.3          4.4
RESTful 单次写入 (1MB)                               10        1.696       17.037        586.9        586.9
RESTful 单次写入 (10MB)                               5       14.734       75.147         66.5        665.4
RESTful 单次写入 (50MB)                               3      120.959      394.350          7.6        380.4
RESTful 单次写入 (100MB)                              2      220.817      508.098          3.9        393.6
RESTful 单次读取 (1KB)                               20        0.140        2.801       7141.2          7.0
RESTful 单次读取 (1MB)                               10        6.175       61.750        161.9        161.9
RESTful 单次读取 (10MB)                               5       71.143      355.716         14.1        140.6
RESTful 单次读取 (50MB)                               3      469.231     1407.694          2.1        106.6
RESTful 单次读取 (100MB)                              2     1709.396     3418.791          0.6         58.5
RESTful 批量写入 (1MB x 10条/批)                        5       79.520      410.060         12.2        121.9
RESTful 批量写入 (10MB x 5条/批)                        3      736.548     2413.489          1.2         62.2
RESTful 并发写入 (1MB x 10并发)                        20       17.778      781.843         25.6         25.6
RESTful 并发写入 (10MB x 5并发)                        10      309.105     2378.779          4.2         42.0

配置说明

本系统采用 Master 统一配置管理 架构:Master 是配置唯一真源,Worker 启动时仅需最小启动信息(worker_id、listen_addr、master_addr、data_dir),其余配置由 Master 在注册时下发。

配置架构

┌─────────────────────────────────────────────────┐
│  master.yaml(配置唯一真源)                     │
│  ├── master:       Master 自身配置               │
│  ├── global:       全局配置                      │
│  ├── worker_defaults: Worker 默认配置(下发)     │
│  └── worker_regions:  worker_id → region 映射    │
└─────────────────────────────────────────────────┘
                      │ gRPC RegisterWorker
                      ▼
┌─────────────────────────────────────────────────┐
│  Worker(注册时获取配置)                         │
│  worker-*.yaml 仅含: worker_id, listen_addr,    │
│                      master_addr, data_dir       │
└─────────────────────────────────────────────────┘

运行模式

# master.yaml
mode: master          # master | worker | standalone

Master 配置(master.yaml)

mode: master
global:
  max_message_size: 268435456      # 256MB
  protocol: "both"                 # grpc | restful | ws | both

master:
  listen_addr: "0.0.0.0:50051"
  meta_path: "master_data/master.db"
  heartbeat_timeout_secs: 30       # Worker 心跳超时
  cleanup_interval_secs: 60        # 宕机 Worker 清理间隔

# Worker 默认配置(Master 持有,注册时下发给 Worker)
worker_defaults:
  kv_ext: ".g3db"
  meta_ext: ".bulk"
  cache_size: 10000
  flush_interval_ms: 5
  heartbeat_interval_secs: 10
  weight: 1
  quad_shard:
    base_level: 8
    split_level: 18
    data_dir: "quad_data"
    kv_ext: ".kv"
    meta_ext: ".db"
    cache_size: 10000
    flush_interval_ms: 5

# Worker 区域分配(worker_id → region,由 Master 统一管理)
# Master 根据 worker_id 在此映射中查找 region,找不到则拒绝注册
worker_regions:
  worker-0: "0"
  worker-1: "1"
  worker-2: "2"
  worker-3: "3"

Worker 配置(worker-*.yaml,极简)

mode: worker
global:
  max_message_size: 268435456
  protocol: "both"
worker:
  worker_id: "worker-0"            # 唯一标识
  listen_addr: "0.0.0.0:50161"     # gRPC 监听地址
  master_addr: "http://127.0.0.1:50051"  # Master 地址
  data_dir: "worker_data/worker-0" # 数据目录
  # 其余配置(kv_ext, meta_ext, cache_size, flush_interval_ms,
  # heartbeat_interval_secs, weight, quad_shard, region)
  # 均由 Master 注册时下发

配置热更新

Master 通过日志 WebSocket 连接的反向通道推送配置更新:

参数类型 可热更新 说明
cache_size ⚠️ 记录 仅记录新值,KvStore 容量需重启生效
flush_interval_ms ⚠️ 记录 仅记录新值,下次 flusher 启动生效
heartbeat_interval_secs ⚠️ 记录 仅记录新值,下次心跳周期生效
weight ⚠️ 记录 仅记录新值
data_dir / kv_path / meta_path 路径类参数需重启生效
kv_ext / meta_ext 扩展名需重启生效

配置版本控制:Master 维护单调递增的 config_version,每次配置变更递增,确保 Worker 能识别配置更新。

数据持久化

  • data/kv.db / worker_data/{id}/kv.db:jammdb KV 数据(B+树,mmap)
  • data/meta.db / worker_data/{id}/meta.db:SQLite 元数据(WAL 模式)
  • write_intent_wal 表:WAL 意图日志(崩溃恢复用)

崩溃恢复

  • jammdb 自身保证 ACID
  • WAL 三步协议保证 KV 和 Meta 的一致性
  • 启动时自动扫描 write_intent_wal 表,补写未完成的 Meta 记录
  • v0.1.1 起:崩溃后数据零丢失(不再丢失 5ms 未刷盘数据)

开发

运行测试

# 全量单元测试
cargo test                    # server + library (37 tests)
cargo test -p store_guardian  # guardian (8 tests)
cargo test --all              # 全部 (47 tests)

# 集成测试
make test       # 启动集群 + 性能测试
make test-fault # 启动集群 + 故障恢复测试

清理数据

make clean-data   # 清理测试数据
make clean        # 清理二进制
make clean-all    # 深度清理

依赖说明

依赖 版本 用途
jammdb 0.11 bbolt 的 Rust 移植,B+树 KV
rusqlite 0.40 SQLite 绑定(bundled)
tonic 0.12 gRPC 框架
warp 0.4 RESTful 框架
tokio 1 异步运行时
moka 0.12 LRU 线程安全缓存
dashmap 6 线程安全哈希表
bytes 1 零拷贝字节处理
chrono 0.4 时间处理
seahash 4 Rendezvous Hashing 路由
serde_yaml 0.9 YAML 配置解析
reqwest 0.12 HTTP 客户端(Master→Worker)
tokio-tungstenite 0.24 WebSocket(Worker 日志推送)
num_cpus 1 CPU 核心数检测
libc 0.2 系统调用(statvfs)

许可证

私有项目,未开源。

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages