Crimson 架构分析:BlueStore 上层逻辑 + SPDK 底层 IO 引擎
1. 概述
本文档分析 Crimson(Ceph 的新实现)的存储架构,重点阐述 Crimson = BlueStore 的上层逻辑 + SPDK 的底层 IO 引擎 这一设计理念。
1.1 架构设计理念
Crimson 的存储架构采用了分层设计:
- 上层逻辑层:复用 BlueStore 的上层逻辑(元数据管理、空间分配、事务处理等)
- 底层 IO 引擎层:使用 SPDK 作为高性能底层 IO 引擎
这种设计既保留了 BlueStore 经过验证的存储逻辑,又通过 SPDK 获得了用户态、零拷贝、轮询模式的高性能 IO 能力。
1.2 Crimson 存储架构
1 | ┌─────────────────────────────────────────────────────────┐ |
2. Crimson 存储架构详解
2.1 AlienStore:适配层
位置: crimson/os/alienstore/
功能:将传统的 BlueStore(同步阻塞式)适配到 Seastar 异步框架
关键实现:
1 | AlienStore::AlienStore(const std::string& type, |
工作原理:
- ThreadPool:创建独立线程池,BlueStore 在此线程池中运行
- Alien 机制:使用
seastar::alien::submit_to()将操作从 Seastar shard 提交到 BlueStore 线程 - 异步桥接:将 BlueStore 的同步回调转换为 Seastar future
示例:
1 | AlienStore::read_errorator::future<ceph::bufferlist> |
2.2 BlueStore:上层逻辑层
位置: src/os/bluestore/
功能:提供对象存储的上层逻辑
主要组件:
元数据管理
Onode:对象元数据Extent:数据范围管理Blob:数据块管理
空间分配器 (
Allocator)AvlAllocator:AVL 树分配器BtreeAllocator:B+ 树分配器BitmapAllocator:位图分配器HybridAllocator:混合分配器
空闲列表管理 (
FreelistManager)- 跟踪空闲空间
- 持久化到 RocksDB
RocksDB 元数据存储
BlueRocksEnv:自定义 RocksDB 环境- 可选:使用 SPDK RocksDB Environment(通过 SPDK BDEV)
BlockDevice 数据 IO
KernelDevice:使用 Linux 内核驱动(传统方式)- 可选:使用 SPDK BDEV(通过 SPDK NVMe Driver)
BlueStore 编译到 Crimson:
1 | set(alien_store_srcs |
2.3 SPDK:底层 IO 引擎层
位置: src/spdk/
功能:提供高性能底层 IO 引擎
主要组件:
SPDK RocksDB Environment (
lib/rocksdb/env_spdk.cc)- 为 RocksDB 提供 SPDK BDEV 后端
- 元数据 IO 通过 SPDK 执行
SPDK BDEV (
lib/bdev/)- 统一的块设备抽象
- 支持 NVMe、AIO、Malloc 等后端
SPDK NVMe Driver (
lib/nvme/)- 用户态 NVMe 驱动
- 轮询模式、零拷贝、低延迟
SPDK 与 BlueStore 的集成方式:
方式 1:RocksDB 元数据 IO(通过 SPDK RocksDB Environment)
1 | BlueStore |
说明:
- BlueStore 的 RocksDB 元数据可以通过 SPDK RocksDB Environment 使用 SPDK BDEV
- 元数据的读写操作通过 SPDK 执行,获得高性能
方式 2:数据 IO(通过 SPDK BDEV)
1 | BlueStore |
说明:
- 数据 IO 可以通过 SPDK BDEV 执行
- 需要实现 BlockDevice 到 SPDK BDEV 的适配层
3. Crimson 与 SPDK 的集成方式
3.1 集成架构总结
根据 Crimson = BlueStore 的上层逻辑 + SPDK 的底层 IO 引擎 这一设计:
1 | ┌─────────────────────────────────────────────────────────┐ |
3.2 当前集成状态
已集成:
- AlienStore 使用 BlueStore:通过
ObjectStore::create()创建 BlueStore 实例 - BlueStore 逻辑复用:完整使用 BlueStore 的上层逻辑(分配器、元数据管理等)
- SPDK RocksDB Environment:SPDK 提供 RocksDB 环境实现,可供 BlueStore 使用
可选集成:
- SPDK BDEV 用于数据 IO:需要实现 BlockDevice 到 SPDK BDEV 的适配层
- 完整 SPDK 集成:元数据和数据 IO 都通过 SPDK 执行
4. 技术实现细节
4.1 线程模型适配
问题:
- Seastar:每个 shard 一个线程,协作式多任务
- BlueStore:同步阻塞式,需要在独立线程中运行
- SPDK:轮询模式,需要在 DPDK 管理的线程中运行
解决方案:
AlienStore ThreadPool
- BlueStore 在独立线程池中运行
- 通过
tp->submit()提交操作
Alien 机制
- 使用
seastar::alien::submit_to()在非 Seastar 线程中执行代码 - 可以用于 SPDK 操作
- 使用
SPDK 线程
- SPDK 在独立线程中运行(通过 DPDK lcore)
- 可以通过 Alien 机制访问
示例:
1 | // 在 Seastar shard 中调用 |
4.2 内存模型适配
问题:
- Seastar:标准 C++ 内存分配
- BlueStore:标准 C++ 内存分配
- SPDK:大页内存、NUMA 感知、IOVA
解决方案:
BlueStore ↔ Seastar
- 使用标准内存,在边界处传递数据
- ThreadPool 保证内存访问安全
BlueStore ↔ SPDK
- 选项 1:使用 SPDK 内存分配(性能更好)
- 选项 2:在边界处拷贝数据(简单但开销)
4.3 异步模型适配
问题:
- Seastar:future/promise 异步模型
- BlueStore:同步阻塞 + 回调
- SPDK:回调或轮询
解决方案:
BlueStore 操作 → Seastar future
1
2
3
4
5
6
7
8
9
10// AlienStore 将 BlueStore 同步操作包装为 future
seastar::future<result> crimson_read(...) {
return tp->submit([=] {
// 同步阻塞操作
return store->read(...);
}).then([] (int r) {
// 转换为 future
return seastar::make_ready_future<result>(...);
});
}SPDK 操作 → Seastar future
1
2
3
4
5
6
7
8
9
10
11seastar::future<> spdk_read(...) {
return seastar::alien::submit_to(spdk_thread_id, [=] {
auto promise = seastar::make_promise<>();
spdk_bdev_read(...,
[](void* ctx, bool success) {
auto p = static_cast<seastar::promise<>*>(ctx);
p->set_value();
}, promise.get());
return promise.get_future();
});
}
5. 性能优势
5.1 使用 SPDK 的优势
用户态驱动
- 避免内核上下文切换
- 减少系统调用开销
轮询模式
- 零延迟响应
- 可预测的性能
零拷贝
- 直接 DMA 访问
- 减少数据拷贝
大页内存
- 减少 TLB miss
- 提高内存访问效率
5.2 架构优势
复用成熟逻辑
- BlueStore 的上层逻辑经过验证
- 减少开发和测试成本
性能优化
- SPDK 提供高性能底层 IO
- 最佳的性能组合
灵活性
- 可以逐步迁移到 SPDK
- 支持混合模式(部分使用 SPDK)
6. 未来发展方向
6.1 完整 SPDK 集成
目标:
- 元数据 IO 使用 SPDK RocksDB Environment
- 数据 IO 使用 SPDK BDEV
- 完整的 SPDK 集成方案
挑战:
- BlockDevice 到 SPDK BDEV 的适配层实现
- 内存模型统一
- 性能测试和优化
6.2 SeaStore vs AlienStore
当前状态:
- SeaStore:Crimson 原生的存储后端(不使用 BlueStore)
- AlienStore:使用 BlueStore 的适配层
未来方向:
- SeaStore 可能成为 Crimson 的默认存储后端
- AlienStore 作为过渡方案或兼容性选项
7. 可能的集成方式(传统方式作为参考)
3.1 方案一:通过 SPDK BDEV 抽象层
架构:
1 | Crimson SeaStore |
实现要点:
创建 SPDK BDEV 适配层
1
2
3
4class SPDKBDevAdapter : public RBMDevice {
// 将 SPDK BDEV 的 C API 适配为 Seastar future
// 需要桥接 SPDK 的轮询模式和 Seastar 的异步模型
};线程模型适配
- SPDK 在独立线程中运行
- 通过消息队列与 Seastar shard 通信
- 使用 Seastar 的
alien机制(已在 Crimson 中存在)
内存模型适配
- SPDK 使用大页内存
- 需要数据拷贝或共享内存
3.2 方案二:使用 SPDK 的 RocksDB 环境
架构:
1 | Crimson SeaStore |
说明:
- SPDK 提供了 RocksDB 环境实现(
lib/rocksdb/env_spdk.cc) - 可以在 RocksDB 层面使用 SPDK
- 但 SeaStore 主要不是基于 RocksDB
3.3 方案三:直接使用 SPDK NVMe API
架构:
1 | Crimson SeaStore |
实现要点:
在独立线程中初始化 SPDK
1
2// SPDK 需要在非 Seastar 线程中运行
// 使用 alien 线程运行 SPDK桥接 SPDK 和 Seastar
1
2
3
4
5
6
7
8
9
10// SPDK I/O 完成回调 → Seastar promise
class SPDKNVMebridge {
seastar::promise<> io_promise;
static void spdk_io_complete(void* ctx, bool success) {
auto bridge = static_cast<SPDKNVMebridge*>(ctx);
// 转换为 Seastar future
bridge->io_promise.set_value();
}
};内存管理
1
2
3// 使用 SPDK 内存池
void* spdk_buffer = spdk_malloc(size, ...);
// 或使用 Seastar 内存,但需要确保兼容性
4. 集成挑战
4.1 线程模型冲突
问题:
- SPDK 期望在 DPDK 管理的线程中运行
- Seastar 有自己的线程模型(每个 shard 一个线程)
解决方案:
- 使用
alien机制在独立线程中运行 SPDK - 通过消息传递与 Seastar shard 通信
4.2 异步模型差异
问题:
- SPDK 使用回调或轮询
- Seastar 使用 future/promise
解决方案:
- 实现适配层,将 SPDK 回调转换为 Seastar future
- 示例:
1 | seastar::future<> spdk_read_async(...) { |
4.3 内存模型差异
问题:
- SPDK 使用大页内存、IOVA
- Seastar 使用标准内存分配
解决方案:
- 选项 1:使用 SPDK 内存分配(性能更好)
- 选项 2:在边界处拷贝数据(简单但性能开销)
5. 实际代码示例(假设集成 SPDK)
如果要在 Crimson 中集成 SPDK,代码可能如下:
5.1 SPDK BDEV 适配器(伪代码)
1 | class SPDKBDevAdapter : public RBMDevice { |
5.2 Alien 线程通信
Crimson 已经支持 alien 机制(用于在非 Seastar 线程中执行代码):
1 | // 在 alien 线程中运行 SPDK |
6. 性能考虑
6.1 使用 SPDK 的优势
- 用户态驱动:避免内核上下文切换
- 轮询模式:零延迟响应
- 零拷贝:直接 DMA 访问
6.2 集成开销
- 线程间通信:alien 调用有开销
- 内存拷贝:如果使用不同的内存模型
- 上下文切换:虽然减少内核切换,但增加了用户态切换
6.3 适用场景
SPDK 集成可能在以下场景更有价值:
- 高频 I/O:大量小 I/O 操作
- 延迟敏感:需要极致延迟的场景
- CPU 充足:可以接受轮询模式的高 CPU 占用
7. 总结
7.1 架构总结
Crimson = BlueStore 的上层逻辑 + SPDK 的底层 IO 引擎
- 上层逻辑层:使用 BlueStore 的成熟逻辑(元数据管理、空间分配、事务处理等)
- 适配层:AlienStore 将 BlueStore 适配到 Seastar 异步框架
- 底层 IO 引擎层:SPDK 提供高性能底层 IO(用户态驱动、轮询模式、零拷贝)
7.2 当前状态
已实现:
- ✅ AlienStore 使用 BlueStore 的上层逻辑
- ✅ BlueStore 的完整功能在 Crimson 中可用
- ✅ SPDK 提供了 RocksDB Environment,可供 BlueStore 使用
可选集成:
- ⚠️ SPDK RocksDB Environment 用于元数据 IO(可选配置)
- ⚠️ SPDK BDEV 用于数据 IO(需要适配层)
7.3 架构优势
复用成熟逻辑
- BlueStore 的上层逻辑经过大规模验证
- 减少开发和测试成本
高性能底层 IO
- SPDK 提供用户态驱动、轮询模式、零拷贝
- 可以获得极致的 IO 性能
灵活性
- 可以逐步集成 SPDK
- 支持混合模式(部分使用 SPDK)
渐进式迁移
- 现有 BlueStore 部署可以平滑迁移到 Crimson
- 通过 AlienStore 实现兼容
7.4 技术要点
线程模型适配
- AlienStore ThreadPool:BlueStore 在独立线程池中运行
- Alien 机制:桥接 Seastar shard 和 BlueStore/SPDK 线程
异步模型适配
- 将 BlueStore 同步操作包装为 Seastar future
- 将 SPDK 回调转换为 Seastar future
内存模型适配
- Seastar/BlueStore:标准 C++ 内存
- SPDK:大页内存、NUMA 感知
- 在边界处处理内存兼容性
7.5 未来方向
完整 SPDK 集成
- 实现 BlockDevice 到 SPDK BDEV 的适配层
- 元数据和数据 IO 都通过 SPDK 执行
性能优化
- 减少线程间通信开销
- 优化内存拷贝
- 性能测试和调优
SeaStore 发展
- SeaStore 可能成为 Crimson 的默认存储后端
- AlienStore 作为过渡方案或兼容性选项
7.4 参考资料
- SPDK NVMe API:
spdk/include/spdk/nvme.h - SPDK BDEV API:
spdk/include/spdk/bdev.h - Crimson NVMe 实现:
crimson/os/seastore/random_block_manager/nvme_block_device.* - Seastar Alien: Seastar 框架的 alien 机制文档
正在加载留言…