SeaStore 物理盘接口与底层库

SeaStore 物理盘接口与底层库

1. 概述

SeaStore 支持多种物理存储设备类型,通过统一的设备抽象接口访问底层存储。所有设备操作最终都基于 Seastar 框架 的异步 I/O 接口实现。

2. 支持的设备类型

2.1 设备类型枚举

位置: seastore_types.h:957

1
2
3
4
5
6
7
8
9
10
11
enum class device_type_t : uint8_t {
NONE = 0,
HDD, // 传统机械硬盘
SSD, // 固态硬盘(段式)
ZBD, // Zoned Block Device (ZNS SSD 或 SMR HDD)
EPHEMERAL_COLD, // 临时设备(冷数据,测试用)
EPHEMERAL_MAIN, // 临时设备(主数据,测试用)
RANDOM_BLOCK_SSD, // 随机块访问 SSD
RANDOM_BLOCK_EPHEMERAL, // 临时随机块设备(测试用)
NUM_TYPES
};

2.2 后端类型分类

设备类型按后端实现分为两类:

1
2
3
4
enum class backend_type_t : uint8_t {
SEGMENTED, // 段式设备:SSD, ZBD, HDD
RANDOM_BLOCK // 随机块设备:RANDOM_BLOCK_SSD
};

映射关系:

  • SEGMENTED: HDD, SSD, ZBD, EPHEMERAL_MAIN, EPHEMERAL_COLD
  • RANDOM_BLOCK: RANDOM_BLOCK_SSD, RANDOM_BLOCK_EPHEMERAL

3. 设备实现与底层库

3.1 段式设备 (SEGMENTED)

3.1.1 BlockSegmentManager (SSD/HDD)

位置: segment_manager/block.h, segment_manager/block.cc

底层库: Seastar DMA 接口

实现方式:

  • 使用 seastar::file::dma_read()dma_write() 进行 I/O
  • 通过 seastar::open_file_dma() 打开设备文件
  • 支持批量 I/O (writev/readv)

关键代码:

1
2
3
4
5
6
7
8
9
10
11
// 打开设备
seastar::open_file_dma(
path,
seastar::open_flags::rw | seastar::open_flags::dsync
)

// 写入
device.dma_write(offset, buffer, length)

// 读取
device.dma_read(offset, buffer, length)

系统调用:

  • Seastar 的 DMA 接口最终调用 Linux AIO (io_submit/io_getevents) 或 io_uring

3.1.2 ZBDSegmentManager (ZBD)

位置: segment_manager/zbd.h, segment_manager/zbd.cc

底层库:

  • Seastar DMA 接口 (基础 I/O)
  • Linux ZBD 接口 (linux/blkzoned.h)

实现方式:

  • 使用 Seastar DMA 进行数据读写
  • 使用 Linux ioctl 进行 Zone 管理操作

Zone 操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <linux/blkzoned.h>

enum class zone_op {
OPEN, // 打开 Zone
FINISH, // 完成 Zone
CLOSE, // 关闭 Zone
RESET // 重置 Zone
};

// 通过 ioctl 操作 Zone
device.ioctl(BLKOPENZONE, ...) // 打开 Zone
device.ioctl(BLKCLOSEZONE, ...) // 关闭 Zone
device.ioctl(BLKFINISHZONE, ...) // 完成 Zone
device.ioctl(BLKRESETZONE, ...) // 重置 Zone
device.ioctl(BLKGETNRZONES, ...) // 获取 Zone 数量

支持的设备:

  • ZNS SSD (NVMe Zoned Namespaces)
  • SMR HDD (Shingled Magnetic Recording)

3.1.3 EphemeralSegmentManager (临时设备)

位置: segment_manager/ephemeral.h, segment_manager/ephemeral.cc

底层库: 内存映射 (用于测试)

实现方式:

  • 使用内存作为存储介质
  • 不涉及实际物理设备

3.2 随机块设备 (RANDOM_BLOCK)

3.2.1 NVMeBlockDevice (RANDOM_BLOCK_SSD)

位置: random_block_manager/nvme_block_device.h, nvme_block_device.cc

底层库:

  • Seastar DMA 接口 (基础 I/O)
  • Linux NVMe ioctl (linux/nvme_ioctl.h)

实现方式:

  • 使用 Seastar DMA 进行常规读写
  • 使用 Linux NVMe ioctl 进行设备特性查询和管理

NVMe 特性支持:

  1. Identify 命令:
1
2
3
4
5
// 识别控制器
co_await identify_controller(device);

// 识别命名空间
co_await identify_namespace(device);
  1. 多流写入 (Multi-Stream):
1
2
3
4
5
// 支持多流写入,通过 stream 参数区分数据生命周期
write_ertr::future<> write(
uint64_t offset,
bufferptr bptr,
uint16_t stream = 0);
  1. 端到端数据保护 (E2E Data Protection):
1
2
3
4
5
6
7
// 检查是否支持端到端数据保护
bool is_end_to_end_data_protection() const;

// 如果支持,使用 NVMe 原生写入
if (is_end_to_end_data_protection()) {
co_await nvme_write(offset, length, buffer);
}
  1. NVMe Passthrough:
1
2
3
4
5
6
7
// 传递 IO 命令
nvme_command_ertr::future<> pass_through_io(
nvme_io_command_t &io_cmd);

// 传递管理命令
nvme_command_ertr::future<> pass_admin(
nvme_admin_command_t &admin_cmd);

关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 打开设备
auto file = co_await seastar::open_file_dma(in_path, mode);
device = std::move(file);

// 识别设备特性
auto id_ctr_data = co_await identify_controller(device);
auto id_ns_data = co_await identify_namespace(device);

// 写入(支持多流)
co_await io_device[stream].dma_write(offset, buffer, length);

// NVMe 原生写入(用于 E2E 保护)
co_await device.ioctl(NVME_IOCTL_IO_CMD, &io_cmd);

3.2.2 EphemeralRBMDevice (临时随机块设备)

位置: random_block_manager/rbm_device.h

底层库: 内存映射 (用于测试)

实现方式:

  • 使用 mmap 分配内存
  • 模拟随机块设备行为

4. 底层库详解

4.1 Seastar 框架

核心库: Seastar (https://github.com/scylladb/seastar)

主要接口:

  1. 文件操作:
1
2
3
4
5
6
7
8
9
10
11
// 打开文件(DMA 模式)
seastar::future<seastar::file> open_file_dma(
const std::string& path,
seastar::open_flags mode
);

// 获取文件状态
seastar::future<seastar::stat_data> file_stat(
const std::string& path,
seastar::follow_symlink follow
);
  1. DMA I/O:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// DMA 写入
seastar::future<size_t> dma_write(
uint64_t pos,
const void* buffer,
size_t len
);

// DMA 读取
seastar::future<size_t> dma_read(
uint64_t pos,
void* buffer,
size_t len
);

// 向量写入
seastar::future<size_t> dma_write(
uint64_t pos,
std::vector<iovec> iov
);
  1. ioctl 支持:
1
2
3
4
5
// 执行 ioctl
seastar::future<int> ioctl(
int request,
void* argp
);

Seastar 底层实现:

  1. Linux AIO:

    • 使用 io_submit() 提交异步 I/O
    • 使用 io_getevents() 获取完成事件
    • 通过 epoll 监听完成事件
  2. io_uring (如果支持):

    • 使用更高效的 io_uring 接口
    • 减少系统调用开销
    • 支持批量提交和完成
  3. 直接 I/O:

    • 绕过页缓存
    • 直接访问存储设备
    • 需要 O_DIRECT 标志

4.2 Linux 内核接口

4.2.1 ZBD 接口

头文件: <linux/blkzoned.h>

ioctl 命令:

  • BLKGETNRZONES: 获取 Zone 数量
  • BLKOPENZONE: 打开 Zone
  • BLKCLOSEZONE: 关闭 Zone
  • BLKFINISHZONE: 完成 Zone
  • BLKRESETZONE: 重置 Zone
  • BLKGETZONESZ: 获取 Zone 大小
  • BLKGETZONEINFO: 获取 Zone 信息

数据结构:

1
2
3
4
5
6
7
8
9
10
11
12
struct blk_zone {
__u64 start; // Zone 起始扇区
__u64 len; // Zone 长度(扇区)
__u64 wp; // 写指针(扇区)
__u8 type; // Zone 类型
__u8 cond; // Zone 状态
__u8 non_seq; // 非顺序写入标志
__u8 reset; // 重置推荐标志
__u8 resv[4];
__u64 capacity; // Zone 容量(扇区)
__u8 resv2[24];
};

4.2.2 NVMe 接口

头文件: <linux/nvme_ioctl.h>

ioctl 命令:

  • NVME_IOCTL_ID: 识别设备
  • NVME_IOCTL_ADMIN_CMD: 执行管理命令
  • NVME_IOCTL_IO_CMD: 执行 I/O 命令
  • NVME_IOCTL_SUBMIT_IO: 提交 I/O(已废弃)

关键数据结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct nvme_passthru_cmd {
__u8 opcode;
__u8 flags;
__u16 rsvd1;
__u32 nsid;
__u32 cdw2;
__u32 cdw3;
__u64 metadata;
__u64 addr;
__u32 metadata_len;
__u32 data_len;
__u32 cdw10;
__u32 cdw11;
__u32 cdw12;
__u32 cdw13;
__u32 cdw14;
__u32 cdw15;
__u32 timeout_ms;
__u32 result;
};

5. 设备选择与配置

5.1 配置参数

主设备类型:

1
seastore_main_device_type = "SSD" | "RANDOM_BLOCK_SSD"

设备路径:

1
2
3
seastore_device_path = "/dev/nvme0n1"  // NVMe 设备
| "/dev/sda" // 块设备
| "/dev/nvme0n1" // ZBD 设备

5.2 设备创建流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Device::make_device(device_path, device_type)

├─► 如果是 SEGMENTED 类型
│ │
│ ├─► device_type == SSD
│ │ │
│ │ ▼
│ │ BlockSegmentManager::create()
│ │
│ ├─► device_type == ZBD
│ │ │
│ │ ▼
│ │ ZBDSegmentManager::create()
│ │
│ └─► device_type == HDD
│ │
│ ▼
│ BlockSegmentManager::create()

└─► 如果是 RANDOM_BLOCK 类型


NVMeBlockDevice::create()

6. 性能特性

6.1 Seastar DMA 优势

  1. 零拷贝:

    • 数据直接从用户缓冲区传输到设备
    • 减少内核拷贝开销
  2. 异步 I/O:

    • 所有操作都是异步的
    • 不阻塞线程
    • 充分利用 CPU
  3. 批量操作:

    • 支持向量 I/O
    • 减少系统调用次数
  4. 事件驱动:

    • 基于 epoll/io_uring
    • 高效的事件处理

6.2 设备特定优化

6.2.1 ZBD 优化

  • 顺序写入: 利用 Zone 的顺序写入特性
  • Zone 管理: 批量重置 Zone,提高效率
  • 写指针跟踪: 自动管理写指针,避免覆盖

6.2.2 NVMe 优化

  • 多流写入: 根据数据生命周期选择流
  • 端到端保护: 利用硬件校验,减少软件开销
  • 原子写入: 利用 NVMe 原子写入单元
  • 写粒度对齐: 根据设备特性对齐写入

7. 与 SPDK 的关系

7.1 SeaStore 不使用 SPDK

重要说明: SeaStore 不直接使用 SPDK。它通过以下方式访问存储:

  1. Seastar DMA 接口: 主要 I/O 路径
  2. Linux 内核接口: ioctl 用于设备管理
  3. POSIX API: 文件操作

7.2 SPDK 在 Ceph 中的使用

SPDK 主要用于 AlienStore (BlueStore 的适配层):

1
2
3
4
5
6
7
8
Crimson OSD

├─► SeaStore (本文档)
│ └─► Seastar DMA

└─► AlienStore
└─► BlueStore
└─► SPDK BDEV

7.3 为什么 SeaStore 不使用 SPDK?

  1. Seastar 已提供高性能 I/O:

    • Seastar 的 DMA 接口已经足够高效
    • 支持 io_uring,性能接近 SPDK
  2. 简化架构:

    • 减少依赖
    • 降低复杂度
  3. 异步模型匹配:

    • Seastar 的异步模型与 SeaStore 完美匹配
    • 无需额外的适配层

8. 总结

8.1 支持的接口

设备类型 底层库 主要接口 特殊功能
SSD/HDD Seastar DMA dma_read/dma_write 批量 I/O
ZBD Seastar DMA + Linux ZBD dma_read/dma_write + ioctl Zone 管理
RANDOM_BLOCK_SSD Seastar DMA + Linux NVMe dma_read/dma_write + ioctl 多流、E2E 保护

8.2 核心库

  1. Seastar:

    • 异步 I/O 框架
    • DMA 接口
    • 事件驱动模型
  2. Linux 内核接口:

    • ZBD: linux/blkzoned.h
    • NVMe: linux/nvme_ioctl.h
  3. 系统调用:

    • AIO: io_submit/io_getevents
    • io_uring: (如果支持)
    • ioctl: 设备管理

8.3 设计特点

  1. 统一抽象: 通过 Device 接口统一不同设备类型
  2. 高性能: 基于 Seastar 的异步 I/O 和零拷贝
  3. 设备优化: 针对不同设备类型提供特定优化
  4. 简化架构: 不依赖 SPDK,减少复杂度

通过这种设计,SeaStore 能够高效地访问各种类型的存储设备,同时保持代码的清晰和可维护性。

文章互动

阅读 --

留言

0 条留言

正在加载留言…