RaftDB 内置了一个高性能、线程安全的嵌入式键值存储引擎。该引擎专为 Raft 状态机设计,支持高并发读写、倒排索引查询以及磁盘空间复用。
数据存储在单个 append-only 文件中 (values.data),但支持空间复用。
物理格式:
[Header][Data]
Flag (1 byte): 0x01 (Valid) 或 0x00 (Deleted)Capacity (4 bytes): 该槽位分配的总大小(包含 Data),用于复用。Length (4 bytes): 实际数据长度。为了减少锁竞争,核心数据结构均采用了分片设计 (Sharding)。
IndexShards (16 Shards):
KeyID -> {FileOffset, CommitIndex} 的映射。KeyMap (16 Shards):
String Key <-> uint32 KeyID 的双向映射。InvertedIndex (16 Shards):
Token -> []KeyID 的倒排表。LIKE 和全文匹配查询。atomic.AddInt64,无需全局锁。测试环境: macOS, 10 并发 Workers, 本地磁盘 IO。
| 操作类型 | 数量 | 耗时 | QPS (Ops/sec) | 说明 |
|---|---|---|---|---|
| Insert | 100,000 | ~2.07s | ~48,300 | 批量写入,完全并行 |
| Update | 10,000 | ~0.09s | ~106,000 | 混合原地更新与追加写 |
| Insert (Reuse) | 5,000 | ~0.27s | ~18,200 | 复用旧空间,无需文件增长 |
| Delete | 10,000 | ~0.02s | ~403,800 | 标记删除,极快 |
结论: FreeList 机制有效工作,长时间运行后数据库文件大小将趋于稳定,不会无限膨胀。
import "db"
// 初始化引擎,指定数据目录
e, err := db.NewEngine("./my_data")
if err != nil {
panic(err)
}
defer e.Close()
// 写入数据 (Key, Value, CommitIndex)
err := e.Set("user.1001", "{\"name\":\"Alice\"}", 1)
// 读取数据
val, found := e.Get("user.1001")
if found {
fmt.Println("Value:", val)
}
支持对 Key、Value 和 CommitIndex 进行查询。
// 查询所有 name 包含 "Alice" 且 CommitIndex > 0 的记录
results, err := e.Query(`value like "*Alice*" commit_index > 0`)
for _, row := range results {
fmt.Printf("Key: %s, Val: %s\n", row.Key, row.Value)
}
KeyMap 和 Index 分片,去除文件 IO 全局锁,使用 pwrite/pread。QPS 提升至 ~49k。StripedLock (Key级锁) 解决并发写冲突和脏读问题。在保证安全的前提下,Update/Delete 性能进一步提升至 100k+ QPS。