SeaStore 架构分析与流程
1. 概述
SeaStore 是 Ceph Crimson OSD 的存储引擎实现,基于 Seastar 框架构建。它采用日志结构存储(Log-Structured Storage)设计,提供高性能的异步存储操作。
1.1 核心特性
- 日志结构存储:所有写入都追加到日志中,提供顺序写入性能
- 事务性操作:支持 ACID 特性的事务处理
- 多 Shard 架构:每个 CPU 核心独立处理 I/O,充分利用多核性能
- 异步清理机制:后台自动回收和整理存储空间
- 多设备支持:支持段式设备(Segment)和随机块设备(Random Block)
2. 架构层次
1 | ┌─────────────────────────────────────────────────────────┐ |
3. 核心组件详解
3.1 SeaStore
位置: seastore.h, seastore.cc
职责:
- 实现
FuturizedStore接口,提供对象存储操作 - 管理多个 Shard,每个 Shard 处理一个 CPU 核心的 I/O
- 提供对象数据、OMAP、属性等存储功能
关键方法:
1 | class SeaStore::Shard { |
3.2 TransactionManager
位置: transaction_manager.h, transaction_manager.cc
职责:
- 管理事务生命周期
- 提供逻辑地址到物理地址的映射(通过 LBA Manager)
- 管理 Extent 的分配和读取
- 提交事务到 Journal
关键方法:
1 | class TransactionManager { |
3.3 Cache
位置: cache.h, cache.cc
职责:
- 管理 Extent 缓存
- 处理事务的 read_set、write_set、retired_set
- 提供 Extent 的读取和分配
- 管理脏页列表
事务三阶段:
- 构造阶段: 用户调用
Cache::create_transaction()并填充事务 - 提交阶段: 用户调用
Cache::try_start_transaction(),如果成功则提交到 Journal - 完成阶段: 事务持久化后,调用
Cache::complete_commit()
关键数据结构:
1 | class Cache { |
3.4 Journal
位置: journal.h, journal/segmented_journal.cc
职责:
- 将事务记录写入持久化存储
- 提供日志回放功能
- 管理日志空间和裁剪
关键方法:
1 | class Journal { |
3.5 SegmentManager
位置: segment_manager.h, segment_manager.cc
职责:
- 管理段式存储设备
- 提供段的分配、释放、写入操作
- 跟踪段的状态(EMPTY/OPEN/CLOSED)
段状态:
EMPTY: 空段,可以分配OPEN: 正在写入的段CLOSED: 已关闭的段,等待清理
3.6 OnodeManager
位置: onode_manager.h, onode_manager/staged-fltree/fltree_onode_manager.cc
职责:
- 管理对象节点(Onode)的创建、查找、删除
- 维护 Onode 树结构
- 提供对象列表功能
关键方法:
1 | class OnodeManager { |
3.7 LBAManager
位置: lba_manager.h, lba/btree_lba_manager.cc
职责:
- 管理逻辑地址(LBA)到物理地址(PBA)的映射
- 提供 B+ 树结构存储映射关系
- 支持间接映射(用于克隆操作)
关键概念:
- 直接映射: LBA 直接映射到物理地址
- 间接映射: LBA 映射到另一个 LBA,用于实现写时复制(COW)
3.8 AsyncCleaner
位置: async_cleaner.h, async_cleaner.cc
职责:
- 后台清理已关闭的段
- 回收无效数据占用的空间
- 管理段的空间利用率
清理策略:
- 基于段的利用率选择清理目标
- 支持多种 GC 算法(GREEDY, BENEFIT, COST_BENEFIT)
4. 数据流程
4.1 写入流程
1 | 用户写入请求 |
详细步骤:
事务创建:
TransactionManager::create_transaction()- 创建新的事务对象
- 初始化事务 ID 和状态
操作执行: 在事务中执行各种操作
_write(): 写入对象数据_setattrs(): 设置属性_omap_set_keys(): 设置 OMAP 键值
事务提交:
TransactionManager::submit_transaction()- 准备记录:
Cache::prepare_record()- 收集所有 dirty extents
- 构建 record_t 结构
- 提交到 Journal:
Journal::submit_record()- 写入日志段
- 等待持久化完成
- 完成提交:
Cache::complete_commit()- 更新 extent 的物理地址
- 标记事务完成
- 准备记录:
4.2 读取流程
1 | 用户读取请求 |
详细步骤:
创建读事务:
TransactionManager::create_transaction(READ)获取 Onode:
OnodeManager::get_onode()- 从 Onode 树中查找对象
- 返回 Onode 引用
读取数据:
ObjectDataHandler::read()- 根据 Onode 中的 LBA 地址读取数据
- 通过
TransactionManager::read_extent()读取 extent
LBA 映射:
LBAManager::get_mapping()- 查找逻辑地址对应的物理地址
- 处理间接映射
缓存查找:
Cache::get_extent_if_cached()- 首先在事务的 read_set 中查找
- 然后在 Cache 的 extents_index 中查找
- 如果未命中,从磁盘读取
4.3 事务冲突处理
SeaStore 使用乐观并发控制(OCC)处理事务冲突:
1 | 事务提交时 |
冲突检测:
- 每个 extent 维护一个版本号或序列号
- 事务提交时检查 read_set 中所有 extent 的版本
- 如果版本发生变化,说明发生了冲突
4.4 日志回放流程
1 | 系统启动 |
回放步骤:
扫描日志: 从日志头开始扫描所有记录
应用 Delta: 对于每个 delta
- 读取对应的 extent
- 应用 delta 变更
- 标记 extent 为 dirty
重建索引:
- 重建 LBA 树
- 重建 Onode 树
- 重建其他元数据结构
验证一致性: 检查所有数据结构的一致性
4.5 清理流程
1 | 后台清理任务 |
清理策略:
段选择:
- 计算每个段的利用率
- 选择利用率低的段进行清理
Extent 扫描:
- 使用 BackrefManager 查找段中的有效 extent
- 确定哪些 extent 仍然被引用
重写:
- 将有效 extent 写入新段
- 更新 LBA 映射
- 提交事务
释放:
- 标记旧段为空
- 更新空间跟踪器
5. 关键数据结构
5.1 Transaction
1 | class Transaction { |
5.2 CachedExtent
1 | class CachedExtent { |
5.3 LBAMapping
1 | struct LBAMapping { |
5.4 record_t
1 | struct record_t { |
6. 地址空间
6.1 逻辑地址 (LBA)
- 范围:
L_ADDR_MIN到L_ADDR_MAX - 用途: 用户可见的地址空间
- 管理: 由 LBAManager 通过 B+ 树管理
6.2 物理地址 (PBA)
SeaStore 支持两种物理地址类型:
段地址 (Segment Address):
paddr_t::make_seg_paddr(segment_id, offset)- 用于段式设备
块地址 (Block Address):
paddr_t::make_blk_paddr(device_id, offset)- 用于随机块设备
6.3 地址转换
1 | 逻辑地址 (LBA) |
7. 并发控制
7.1 Shard 隔离
- 每个 CPU 核心运行一个独立的 Shard
- Shard 之间通过消息传递通信
- 每个 Shard 有独立的 Cache 和 TransactionManager
7.2 事务隔离
- 读事务: 可以并发执行
- 写事务: 通过 OrderingHandle 保证顺序
- 冲突检测: 使用乐观并发控制
7.3 锁机制
- Extent 锁: 每个 extent 维护读事务集合
- 段锁: 段写入时加锁
- 集合锁:
SeastoreCollection::ordering_lock保证操作顺序
8. 性能优化
8.1 缓存策略
- LRU 缓存: 使用 ExtentPinboard 管理缓存优先级
- 部分读取: 支持 extent 的部分范围读取
- 预取: 可以预取相关 extent
8.2 写入优化
- 批量提交: 多个操作合并到一个事务
- 顺序写入: 日志结构保证顺序写入性能
- 异步提交: 写入操作异步完成
8.3 清理优化
- 增量清理: 每次只清理部分段
- 智能选择: 基于利用率选择清理目标
- 并行清理: 可以并行处理多个段
9. 错误处理
9.1 错误类型
input_output_error: I/O 错误enospc: 空间不足eagain: 事务冲突,需要重试enoent: 对象不存在value_too_large: 值过大
9.2 错误恢复
- 事务回滚: 冲突时自动回滚
- 日志回放: 系统重启时从日志恢复
- 一致性检查: 定期检查数据结构一致性
10. 总结
SeaStore 是一个高性能的日志结构存储引擎,具有以下特点:
- 架构清晰: 分层设计,职责明确
- 高性能: 充分利用多核和异步 I/O
- 可靠性: 事务性保证和数据一致性
- 可扩展: 支持多种存储设备和配置
通过日志结构存储和异步清理机制,SeaStore 在保证数据一致性的同时,提供了优异的写入性能。
正在加载留言…