RocksDB基础架构 #
一、整体架构 #
1.1 架构概览 #
RocksDB采用分层架构设计,从上到下分为API层、核心层和存储层。
text
┌─────────────────────────────────────────────────────┐
│ 应用程序 │
├─────────────────────────────────────────────────────┤
│ API层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ DB │ │ Iterator │ │ Snapshot │ │
│ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────┤
│ 核心层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ MemTable │ │ WAL │ │ Version │ │
│ │ Manager │ │ Manager │ │ Set │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Compaction│ │ Flush │ │ Cache │ │
│ │ Job │ │ Job │ │ Manager │ │
│ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────┤
│ 存储层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ SST │ │ Block │ │ Filter │ │
│ │ Files │ │ Cache │ │ Block │ │
│ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────┤
│ 文件系统 │
└─────────────────────────────────────────────────────┘
1.2 核心组件 #
| 组件 | 功能 | 位置 |
|---|---|---|
| DB | 数据库主接口 | API层 |
| MemTable | 内存写入缓冲 | 核心层 |
| WAL | 预写日志 | 核心层 |
| SST Files | 磁盘数据文件 | 存储层 |
| Block Cache | 数据块缓存 | 存储层 |
| Version Set | 版本管理 | 核心层 |
二、LSM-Tree存储结构 #
2.1 LSM-Tree简介 #
LSM-Tree(Log-Structured Merge-Tree)是一种写入优化的数据结构,由Patrick O’Neil等人于1996年提出。
核心思想:
text
传统B+Tree:随机写入 → 性能差
LSM-Tree: 顺序写入 → 性能优
2.2 LSM-Tree层级结构 #
text
写入请求
↓
┌──────────────────────────────────────┐
│ Active MemTable │
│ (可变内存表) │
└──────────────────┬───────────────────┘
│ 写满后转为不可变
↓
┌──────────────────────────────────────┐
│ Immutable MemTable │
│ (不可变内存表) │
└──────────────────┬───────────────────┘
│ 后台Flush线程
↓
┌──────────────────────────────────────┐
│ Level 0 │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │SST │ │SST │ │SST │ │SST │ │
│ └────┘ └────┘ └────┘ └────┘ │
│ (文件可能有重叠) │
└──────────────────┬───────────────────┘
│ Compaction
↓
┌──────────────────────────────────────┐
│ Level 1 │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │SST │ │SST │ │SST │ │SST │ │
│ └────┘ └────┘ └────┘ └────┘ │
│ (文件无重叠,有序) │
└──────────────────┬───────────────────┘
│ Compaction
↓
┌──────────────────────────────────────┐
│ Level 2 │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ... │
│ │SST │ │SST │ │SST │ │SST │ │
│ └────┘ └────┘ └────┘ └────┘ │
└──────────────────────────────────────┘
...
2.3 层级大小关系 #
text
Level 0: 大小不限,文件可重叠
Level 1: 大小 = 10 * Level 0 文件大小
Level 2: 大小 = 10 * Level 1 大小
Level N: 大小 = 10 * Level N-1 大小
| Level | 文件大小 | 文件数量 | 总大小 |
|---|---|---|---|
| L0 | 64MB | 不限 | 不限 |
| L1 | 64MB | 10 | 640MB |
| L2 | 64MB | 100 | 6.4GB |
| L3 | 64MB | 1000 | 64GB |
| L4 | 64MB | 10000 | 640GB |
三、写入流程 #
3.1 写入路径 #
text
写入请求
│
↓
┌─────────────┐
│ 写入WAL日志 │ ← 保证持久性
└──────┬──────┘
│
↓
┌─────────────┐
│ 写入MemTable │ ← 内存跳表
└──────┬──────┘
│
↓
返回成功
3.2 MemTable结构 #
MemTable是基于跳表(Skip List)实现的有序内存表。
text
跳表结构:
Level 4: Head ─────────────────────────────→ Tail
│ │
Level 3: Head ─────→ Node3 ──────────────→ Tail
│ │ │
Level 2: Head ─→ Node1 ─→ Node3 ─→ Node5 ─→ Tail
│ │ │ │ │
Level 1: Head ─→ Node1 ─→ Node2 ─→ Node3 ─→ Node4 ─→ Node5 ─→ Tail
│ │ │ │ │ │
Level 0: Head ─→ Node1 ─→ Node2 ─→ Node3 ─→ Node4 ─→ Node5 ─→ Tail
(key1) (key2) (key3) (key4) (key5)
跳表特点:
| 特性 | 说明 |
|---|---|
| 有序性 | 按键排序 |
| 查找复杂度 | O(log n) |
| 插入复杂度 | O(log n) |
| 空间复杂度 | O(n) |
| 并发友好 | 支持无锁读取 |
3.3 WAL机制 #
WAL(Write-Ahead Log)保证数据持久性。
text
WAL写入流程:
写入请求
│
↓
┌─────────────────┐
│ 序列化记录 │
│ (key, value, │
│ sequence, │
│ type) │
└────────┬────────┘
│
↓
┌─────────────────┐
│ 追加到WAL文件 │
│ (顺序写入) │
└────────┬────────┘
│
↓
┌─────────────────┐
│ sync到磁盘 │
│ (可选) │
└─────────────────┘
WAL记录格式:
text
┌────────────────────────────────────────┐
│ Header (7 bytes) │
├────────────────────────────────────────┤
│ ┌─────────┬─────────┬───────────────┐ │
│ │ CRC (4B)│ Size (2B)│ Type (1B) │ │
│ └─────────┴─────────┴───────────────┘ │
├────────────────────────────────────────┤
│ Payload │
│ ┌────────────────────────────────────┐│
│ │ LogRecord (key, value, sequence) ││
│ └────────────────────────────────────┘│
└────────────────────────────────────────┘
四、Flush流程 #
4.1 Flush触发条件 #
cpp
// MemTable写满
options.write_buffer_size = 64 * 1024 * 1024; // 64MB
// MemTable数量达到上限
options.max_write_buffer_number = 4;
// 触发条件
if (memtable_size >= write_buffer_size) {
// 切换到Immutable MemTable
// 触发Flush
}
4.2 Flush过程 #
text
Active MemTable写满
│
↓
┌───────────────────┐
│ 切换为Immutable │
│ 创建新Active │
└─────────┬─────────┘
│
↓
┌───────────────────┐
│ 后台Flush线程 │
│ 遍历Immutable │
└─────────┬─────────┘
│
↓
┌───────────────────┐
│ 生成SST文件 │
│ 写入Level 0 │
└─────────┬─────────┘
│
↓
┌───────────────────┐
│ 更新Version │
│ 删除Immutable │
└───────────────────┘
五、Compaction流程 #
5.1 Compaction类型 #
1. Leveled Compaction(默认)
text
Level N → Level N+1
L0文件重叠,需要与L1合并:
┌─────────────────────────────────────┐
│ L0: [a-d] [c-f] [e-h] (重叠) │
│ ↓ │
│ L1: [a-c] [d-f] [g-i] (有序) │
│ ↓ │
│ 合并后L1: [a-c] [c-f] [f-h] [h-i] │
└─────────────────────────────────────┘
2. Tiered Compaction
text
多层合并,减少写放大
Level N → Level N+1 (不立即合并)
等到Level N+1文件足够多再合并
3. FIFO Compaction
text
先进先出,适合时序数据
旧数据自动删除:
[oldest] → [older] → [newer] → [newest]
↓
删除
5.2 Compaction触发条件 #
cpp
// Level大小触发
if (level_size > level_max_size) {
trigger_compaction();
}
// 文件数量触发(L0)
if (level0_file_num > level0_file_num_trigger) {
trigger_compaction();
}
// 手动触发
db->CompactRange(CompactRangeOptions(), begin, end);
5.3 Compaction过程 #
text
选择Compaction文件
│
↓
┌───────────────────┐
│ 确定输入文件 │
│ (Level N和N+1) │
└─────────┬─────────┘
│
↓
┌───────────────────┐
│ 多路归并排序 │
│ (Iterator合并) │
└─────────┬─────────┘
│
↓
┌───────────────────┐
│ 生成新SST文件 │
│ 写入Level N+1 │
└─────────┬─────────┘
│
↓
┌───────────────────┐
│ 原子更新Version │
│ 删除旧文件 │
└───────────────────┘
六、读取流程 #
6.1 读取路径 #
text
读取请求(key)
│
↓
┌─────────────────────┐
│ 检查MemTable │
│ (Active + Immutable)│
└──────────┬──────────┘
│ 未找到
↓
┌─────────────────────┐
│ 检查Block Cache │
└──────────┬──────────┘
│ 未命中
↓
┌─────────────────────┐
│ 查找Level 0 │
│ (所有文件) │
└──────────┬──────────┘
│ 未找到
↓
┌─────────────────────┐
│ 查找Level 1~N │
│ (二分查找文件) │
└──────────┬──────────┘
│
↓
返回结果
6.2 SST文件查找 #
text
SST文件结构:
┌────────────────────────────────────┐
│ Data Block 1 │
├────────────────────────────────────┤
│ Data Block 2 │
├────────────────────────────────────┤
│ ... │
├────────────────────────────────────┤
│ Meta Block (Filter) │
├────────────────────────────────────┤
│ Meta Index Block │
├────────────────────────────────────┤
│ Index Block │
├────────────────────────────────────┤
│ Footer │
└────────────────────────────────────┘
查找过程:
1. 读取Footer → 获取Index Block位置
2. 二分查找Index Block → 定位Data Block
3. 检查Filter Block → 快速排除
4. 读取Data Block → 查找key
6.3 布隆过滤器 #
cpp
// 启用布隆过滤器
rocksdb::BlockBasedTableOptions table_options;
table_options.filter_policy.reset(
rocksdb::NewBloomFilterPolicy(10) // 10 bits per key
);
options.table_factory.reset(
rocksdb::NewBlockBasedTableFactory(table_options)
);
text
布隆过滤器原理:
插入:key → 多个hash函数 → 设置bit位
查询:key → 多个hash函数 → 检查bit位
结果:
- 所有位都为1 → 可能存在(需进一步确认)
- 有位为0 → 一定不存在(直接跳过)
七、版本管理 #
7.1 Version Set #
Version Set管理数据库的当前状态。
text
Version Set结构:
┌─────────────────────────────────────┐
│ Version Set │
├─────────────────────────────────────┤
│ Current Version │
│ ┌───────────────────────────────┐ │
│ │ Level 0: [file1, file2, ...] │ │
│ │ Level 1: [file3, file4, ...] │ │
│ │ Level 2: [file5, file6, ...] │ │
│ │ ... │ │
│ └───────────────────────────────┘ │
├─────────────────────────────────────┤
│ Version History (链表) │
│ ┌─────────┐ ┌─────────┐ │
│ │Version 1│→│Version 2│→ ... │
│ └─────────┘ └─────────┘ │
├─────────────────────────────────────┤
│ MANIFEST File │
│ (记录版本变更) │
└─────────────────────────────────────┘
7.2 MANIFEST文件 #
MANIFEST记录数据库元数据的变更。
text
MANIFEST内容:
- 数据库启动时的状态
- SST文件的添加/删除
- Compaction产生的变化
- 列族的创建/删除
格式:
┌────────────────────────────────────┐
│ Record 1 (Add file xxx to Level 0) │
├────────────────────────────────────┤
│ Record 2 (Delete file yyy) │
├────────────────────────────────────┤
│ Record 3 (Add file zzz to Level 1) │
├────────────────────────────────────┤
│ ... │
└────────────────────────────────────┘
八、列族架构 #
8.1 列族概念 #
列族(Column Family)是RocksDB的逻辑分区机制。
text
数据库
├── 默认列族 (default)
│ └── 独立的MemTable、SST文件
├── 列族A
│ └── 独立的MemTable、SST文件
└── 列族B
└── 独立的MemTable、SST文件
8.2 列族特点 #
| 特点 | 说明 |
|---|---|
| 数据隔离 | 每个列族独立存储 |
| 配置独立 | 每个列族可独立配置 |
| 共享WAL | 所有列族共享WAL |
| 原子写入 | 跨列族写入原子性 |
8.3 列族存储结构 #
text
写入流程:
写入请求(cf1, key1, value1)
写入请求(cf2, key2, value2)
│
↓
┌─────────────────┐
│ 写入共享WAL │
│ (包含列族ID) │
└────────┬────────┘
│
↓
┌─────────────────────────────────┐
│ 写入各自的MemTable │
│ cf1 → MemTable1 │
│ cf2 → MemTable2 │
└─────────────────────────────────┘
九、缓存架构 #
9.1 Block Cache #
Block Cache缓存SST文件的数据块。
cpp
// 创建Block Cache
std::shared_ptr<Cache> cache = NewLRUCache(
1024 * 1024 * 1024, // 1GB容量
8 // 分片数
);
BlockBasedTableOptions table_options;
table_options.block_cache = cache;
9.2 缓存层次 #
text
读取请求
│
↓
┌─────────────────┐
│ Block Cache │ ← LRU缓存
│ (热数据块) │
└────────┬────────┘
│ 未命中
↓
┌─────────────────┐
│ OS Page Cache │ ← 操作系统缓存
└────────┬────────┘
│ 未命中
↓
┌─────────────────┐
│ 磁盘 │
└─────────────────┘
十、总结 #
10.1 核心组件关系 #
text
写入: WAL → MemTable → Immutable → SST(L0) → SST(L1~N)
读取: MemTable → Block Cache → SST Files
维护: Flush → Compaction → Version Update
10.2 关键概念 #
| 概念 | 说明 |
|---|---|
| MemTable | 内存写入缓冲 |
| WAL | 预写日志,保证持久性 |
| SST | 磁盘数据文件 |
| Flush | 内存表刷盘 |
| Compaction | 文件合并压缩 |
| Version | 数据库快照状态 |
下一步,让我们开始RocksDB快速入门实践!
最后更新:2026-03-27