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