存储层 #

一、存储层概述 #

1.1 存储架构 #

text
存储层架构
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   事务层                                                    │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              MVCC 层                                │   │
│   │   多版本并发控制                                   │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              Pebble 存储引擎                        │   │
│   │   LSM-Tree 结构                                    │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              文件系统                               │   │
│   │   ext4 / xfs                                       │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       ▼                                                     │
│   磁盘存储                                                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 核心组件 #

组件 职责
MVCC 多版本并发控制
Pebble 存储引擎
Block Cache 数据缓存
WAL 预写日志

二、Pebble存储引擎 #

2.1 LSM-Tree结构 #

text
LSM-Tree 结构
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   写入流程:                                                 │
│                                                             │
│   写入请求                                                  │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              Write Ahead Log (WAL)                  │   │
│   │   顺序写入,保证持久性                              │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              MemTable (Active)                      │   │
│   │   内存中的有序表,新数据写入                       │   │
│   │   默认大小: 4MB                                     │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       │ MemTable 满了                                       │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              MemTable (Immutable)                   │   │
│   │   等待刷盘的内存表                                  │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       │ 后台刷盘                                            │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              SSTable (Sorted String Table)          │   │
│   │                                                      │   │
│   │   Level 0: 直接从 MemTable 刷盘                     │   │
│   │   Level 1-6: 合并压缩后的文件                       │   │
│   │                                                      │   │
│   │   ┌─────────────────────────────────────────────┐   │   │
│   │   │ L0: 文件可能有重叠,查询需要检查多个文件   │   │   │
│   │   │ L1-L6: 文件有序,查询效率高                │   │   │
│   │   └─────────────────────────────────────────────┘   │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2.2 读取流程 #

text
读取流程
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   读取请求                                                  │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              Block Cache                            │   │
│   │   检查缓存                                          │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       │ 未命中                                              │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              MemTable (Active)                      │   │
│   │   检查活跃内存表                                    │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       │ 未找到                                              │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              MemTable (Immutable)                   │   │
│   │   检查不可变内存表                                  │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       │ 未找到                                              │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              SSTable (L0 → L1 → ... → L6)           │   │
│   │   从 L0 开始逐层查找                                │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       ▼                                                     │
│   返回结果                                                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2.3 Compaction #

text
Compaction (压缩合并)
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   目的:                                                     │
│   ├── 合并多个 SSTable                                     │
│   ├── 删除过期数据                                         │
│   ├── 清理已删除数据                                       │
│   └── 减少查询需要检查的文件                               │
│                                                             │
│   触发条件:                                                 │
│   ├── L0 文件数超过阈值                                    │
│   ├── 某层大小超过阈值                                     │
│   └── 手动触发                                             │
│                                                             │
│   过程:                                                     │
│                                                             │
│   L0 → L1:                                                  │
│   ┌─────────────────────────────────────────────────────┐   │
│   │ L0: [A] [B] [C]  (可能有重叠)                       │   │
│   │          │                                          │   │
│   │          ▼                                          │   │
│   │ L1: [D] [E] [F]  (无重叠)                          │   │
│   │          │                                          │   │
│   │          ▼                                          │   │
│   │ 合并后: [G] [H] [I] [J]                            │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
│   写放大:                                                   │
│   每层数据量是上一层的10倍                                  │
│   总写放大: ~10x * 7层 = ~50-100x                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

三、MVCC实现 #

3.1 多版本数据 #

text
MVCC 数据结构
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   Key-Value 存储:                                           │
│                                                             │
│   Key: /Table/<table_id>/<index_id>/<primary_key>          │
│   Value: <timestamp> + <value>                              │
│                                                             │
│   示例:                                                     │
│                                                             │
│   Key: /Table/53/1/1                                        │
│                                                             │
│   版本历史:                                                 │
│   ┌─────────────────────────────────────────────────────┐   │
│   │ Timestamp: 100                                      │   │
│   │ Value: {id: 1, name: "Alice", age: 25}             │   │
│   ├─────────────────────────────────────────────────────┤   │
│   │ Timestamp: 50                                       │   │
│   │ Value: {id: 1, name: "Alice", age: 24}             │   │
│   ├─────────────────────────────────────────────────────┤   │
│   │ Timestamp: 10                                       │   │
│   │ Value: {id: 1, name: "Alice", age: 23}             │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
│   读取时:                                                   │
│   ├── 根据时间戳选择版本                                   │
│   └── 默认读取最新版本                                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

3.2 时间戳 #

sql
-- HLC (混合逻辑时钟)
-- 结合物理时钟和逻辑时钟

-- 时间旅行查询
SELECT * FROM users 
AS OF SYSTEM TIME '-10s';

-- 查看历史数据
SELECT * FROM users 
AS OF SYSTEM TIME '2024-01-01 00:00:00';

-- 使用时间戳
SELECT * FROM users 
AS OF SYSTEM TIME 1234567890;

3.3 垃圾回收 #

text
MVCC 垃圾回收
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   GC 配置:                                                  │
│   ├── 默认保留时间: 25小时                                 │
│   ├── 定期执行GC                                           │
│   └── 清理旧版本数据                                       │
│                                                             │
│   配置GC策略:                                               │
│                                                             │
│   ALTER DATABASE defaultdb                                  │
│   CONFIGURE ZONE USING                                      │
│       gc.ttlseconds = 86400;  -- 24小时                    │
│                                                             │
│   GC 流程:                                                  │
│                                                             │
│   1. 扫描Range                                              │
│      │                                                      │
│      ▼                                                      │
│   2. 识别过期版本                                           │
│      │                                                      │
│      ▼                                                      │
│   3. 删除旧版本                                             │
│      │                                                      │
│      ▼                                                      │
│   4. 触发Compaction                                         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

四、Block Cache #

4.1 缓存结构 #

text
Block Cache 结构
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   缓存层次:                                                 │
│                                                             │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              SSTable Block Cache                    │   │
│   │   缓存数据块                                        │   │
│   │   默认大小: 总内存的 50%                            │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              Index Block Cache                      │   │
│   │   缓存索引块                                        │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              Filter Block Cache                     │   │
│   │   缓存布隆过滤器                                    │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
│   缓存策略:                                                 │
│   ├── LRU (最近最少使用)                                   │
│   └── 分片缓存 (减少锁竞争)                                │
│                                                             │
└─────────────────────────────────────────────────────────────┘

4.2 缓存配置 #

bash
# 启动时配置缓存大小
cockroach start --cache=4GB

# 推荐配置
# cache = 总内存的 50%
# 例如: 16GB 内存 -> 8GB cache

五、WAL预写日志 #

5.1 WAL机制 #

text
WAL 机制
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   写入流程:                                                 │
│                                                             │
│   写入请求                                                  │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              写入 WAL                               │   │
│   │   顺序写入磁盘                                      │   │
│   │   保证持久性                                        │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              写入 MemTable                          │   │
│   │   内存写入                                          │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       ▼                                                     │
│   返回成功                                                  │
│                                                             │
│   恢复流程:                                                 │
│                                                             │
│   节点重启                                                  │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              读取 WAL                               │   │
│   │   重放日志                                          │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              恢复 MemTable                          │   │
│   │   重建内存状态                                      │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

5.2 WAL配置 #

bash
# WAL 目录配置
cockroach start --store=path=/data,wal-dir=/wal

# 同步配置
--wal-sync-interval=32KB

六、数据编码 #

6.1 Key编码 #

text
Key 编码格式
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   主键索引:                                                 │
│   /Table/<table_id>/<index_id>/<primary_key>               │
│                                                             │
│   示例:                                                     │
│   /Table/53/1/1          (表53, 主键索引, 主键值1)         │
│   /Table/53/1/'user1'    (字符串主键)                      │
│                                                             │
│   二级索引:                                                 │
│   /Table/<table_id>/<index_id>/<index_value>/<primary_key> │
│                                                             │
│   示例:                                                     │
│   /Table/53/2/'user@example.com'/1                         │
│   (表53, 索引2, 邮箱值, 主键)                              │
│                                                             │
│   编码特点:                                                 │
│   ├── 有序编码                                             │
│   ├── 支持范围扫描                                         │
│   └── 前缀压缩                                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

6.2 Value编码 #

text
Value 编码格式
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   格式: <timestamp> + <value>                               │
│                                                             │
│   Timestamp:                                                │
│   ├── 事务时间戳                                           │
│   └── 用于MVCC版本控制                                     │
│                                                             │
│   Value:                                                    │
│   ├── 行数据编码                                           │
│   ├── 列值序列化                                           │
│   └── 支持NULL值                                           │
│                                                             │
│   示例:                                                     │
│   Timestamp: 1234567890.123456789                          │
│   Value: {id: 1, name: "Alice", age: 25}                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

七、存储配置 #

7.1 存储参数 #

bash
# 启动参数
cockroach start \
    --store=path=/data,size=100GB \
    --cache=8GB \
    --max-sql-memory=4GB

# 存储选项
--store=path=<path>,size=<size>,ballast-size=<size>

# 缓存选项
--cache=<size>

# SQL内存选项
--max-sql-memory=<size>

7.2 性能调优 #

text
存储性能调优
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   硬件建议:                                                 │
│   ├── SSD (推荐 NVMe)                                      │
│   ├── 足够的内存                                           │
│   └── 独立的WAL磁盘                                        │
│                                                             │
│   配置建议:                                                 │
│   ├── cache = 总内存的 50%                                 │
│   ├── max-sql-memory = 总内存的 25%                        │
│   └── wal-dir = 独立磁盘                                   │
│                                                             │
│   监控指标:                                                 │
│   ├── 缓存命中率                                           │
│   ├── Compaction速度                                       │
│   ├── 写放大                                               │
│   └── 磁盘IOPS                                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

八、总结 #

存储层要点:

组件 功能
Pebble LSM-Tree存储引擎
MVCC 多版本并发控制
Block Cache 数据缓存
WAL 预写日志

下一步,让我们学习分布式层!

最后更新:2026-03-27