SPDK 硬盘管理总体架构分析

SPDK 硬盘管理总体架构分析

1. 概述

SPDK(Storage Performance Development Kit)通过多层架构管理硬盘设备,从底层的物理设备发现到上层的块设备抽象,实现了高性能、用户态的存储管理方案。

1.1 核心设计理念

  • 用户态驱动:避免内核上下文切换开销
  • 轮询模式:消除中断延迟,实现零延迟响应
  • 模块化设计:通过 BDEV 抽象层统一管理不同类型的存储设备
  • 热插拔支持:动态发现和管理设备

1.2 核心存储栈架构

根据 SPDK 的实际实现,硬盘管理的核心架构如下:

1
2
3
4
5
6
7
8
9
10
11
上层协议和应用 (NVMe-oF / iSCSI / vhost / 应用)

lvol (逻辑卷管理)

Blobstore (真正的磁盘空间管理核心)

bdev (统一块设备抽象层)

NVMe Driver (用户态,轮询模式)

NVMe SSD (物理硬件)

关键要点

  1. Blobstore 是核心:Blobstore 是真正的磁盘空间管理核心,负责:

    • 磁盘空间的分配和回收
    • 元数据的持久化和管理
    • Blob(可变大小对象)的生命周期管理
    • Cluster(存储单元)的分配
  2. lvol 基于 Blobstore:逻辑卷(lvol)是建立在 Blobstore 之上的高级抽象:

    • 每个逻辑卷对应 Blobstore 上的一个 Blob
    • 提供快照、克隆等高级功能
    • 提供块设备接口给上层协议使用
  3. bdev 提供统一接口:bdev 抽象层提供统一的块设备接口,支持多种后端:

    • 可以是直接访问(如 NVMe BDEV)
    • 也可以是基于 Blobstore(如 lvol BDEV)

2. 架构总览

2.1 核心存储栈架构图

根据 SPDK 的实际实现,核心存储栈如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
┌─────────────────────────────────────────────────────────────────┐
│ 上层协议和应用层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │NVMe-oF │ │ iSCSI │ │ vhost │ │ 应用 │ │
│ │ Target │ │ Target │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ lvol (逻辑卷管理) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ lib/lvol/lvol.c │ │
│ │ - 逻辑卷存储 (lvol store) 管理 │ │
│ │ - 逻辑卷 (lvol) 生命周期管理 │ │
│ │ - 快照和克隆支持 │ │
│ │ - 基于 Blobstore 的 Blob │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ Blobstore (真正的磁盘空间管理核心) ⭐ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ lib/blob/blobstore.c │ │
│ │ - 磁盘空间分配和回收 │ │
│ │ - 元数据持久化和管理 │ │
│ │ - Blob (可变大小对象) 管理 │ │
│ │ - Cluster (存储单元) 分配 │ │
│ │ - Page (元数据页) 管理 │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ bdev (统一块设备抽象层) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ lib/bdev/bdev.c │ │
│ │ - 设备注册/注销 │ │
│ │ - I/O 请求路由 │ │
│ │ - QoS 控制 │ │
│ │ - Channel 管理 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ BDEV 模块: │ │
│ │ - NVMe BDEV: 直接访问 NVMe 设备 │ │
│ │ - Lvol BDEV: 基于 Blobstore 的逻辑卷 │ │
│ │ - AIO/Malloc/PMEM/RBD/RAID 等 │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ NVMe Driver (用户态,轮询模式) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ lib/nvme/nvme_ctrlr.c, nvme_pcie.c │ │
│ │ - 控制器管理 │ │
│ │ - 命名空间管理 │ │
│ │ - 队列对管理 │ │
│ │ - 轮询模式 I/O │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ NVMe SSD (物理硬件) │
│ PCIe NVMe 固态硬盘 │
└─────────────────────────────────────────────────────────────────┘

2.2 关键路径说明

路径 1: 直接访问路径(不使用 Blobstore)

1
应用 → bdev → NVMe BDEV → NVMe Driver → NVMe SSD

适用于:直接访问物理设备,无需高级存储管理功能

路径 2: 存储管理路径(使用 Blobstore + lvol)⭐

1
应用 → lvol → Blobstore → bdev → NVMe BDEV → NVMe Driver → NVMe SSD

适用于:需要逻辑卷管理、快照、克隆等高级功能

3. 核心组件详解

3.1 BDEV 抽象层 (Block Device Abstraction Layer)

位置: lib/bdev/bdev.c

功能: SPDK 的块设备抽象层核心,提供统一的块设备接口。

主要职责:

  1. 设备管理

    • 设备的注册和注销
    • 设备查询和枚举
    • 设备生命周期管理
  2. I/O 管理

    • I/O 请求的路由和分发
    • I/O 缓冲区的分配和管理
    • I/O 完成回调处理
  3. QoS 控制

    • I/O 速率限制(IOPS、带宽)
    • 读写分离的速率控制
    • 时间片(timeslice)机制
  4. Channel 管理

    • 每线程的 I/O channel 创建
    • Channel 和共享资源的关联
    • 多 channel 共享管理

关键数据结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// BDEV 管理器(全局单例)
struct spdk_bdev_mgr {
struct spdk_mempool *bdev_io_pool; // I/O 对象内存池
struct spdk_mempool *buf_small_pool; // 小缓冲区内存池
struct spdk_mempool *buf_large_pool; // 大缓冲区内存池
void *zero_buffer; // 零缓冲区

TAILQ_HEAD(, spdk_bdev_module) bdev_modules; // BDEV 模块链表
struct spdk_bdev_list bdevs; // 已注册的 BDEV 设备链表

bool init_complete; // 初始化完成标志
pthread_mutex_t mutex; // 互斥锁
};

// BDEV 设备结构
struct spdk_bdev {
char *name; // 设备名称
struct spdk_bdev_module *module; // 所属模块
struct spdk_bdev_fn_table *fn_table; // 函数表(读、写、刷盘等)

uint64_t blockcnt; // 总块数
uint32_t blocklen; // 块大小
uint32_t optimal_io_boundary; // 最优 I/O 边界

struct spdk_bdev_qos *qos; // QoS 配置

TAILQ_ENTRY(spdk_bdev) link; // 链表节点
};

3.2 Blobstore (真正的磁盘空间管理核心) ⭐

位置: lib/blob/blobstore.c

功能: Blobstore 是 SPDK 中真正的磁盘空间管理核心,负责磁盘空间的分配、回收和元数据管理。

核心职责:

  1. 磁盘空间管理

    • Cluster(存储单元,默认 1MB)的分配和回收
    • 空闲空间的管理和跟踪
    • 空间碎片整理
  2. 元数据管理

    • 元数据的持久化(存储在设备上)
    • 元数据页(Page)的管理
    • 元数据的同步和恢复
  3. Blob 对象管理

    • Blob(可变大小对象)的创建、删除、打开、关闭
    • Blob 数据的读、写、擦除操作
    • Blob 快照和克隆支持
  4. I/O 路径优化

    • 元数据操作和 I/O 操作分离
    • 元数据线程和 I/O 线程分离
    • 无锁设计的 I/O 路径

关键数据结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Blobstore 结构
struct spdk_blob_store {
struct spdk_bs_dev *dev; // 底层块设备
uint64_t total_clusters; // 总集群数
uint64_t free_clusters; // 空闲集群数
uint32_t cluster_sz; // 集群大小(默认 1MB)
uint32_t page_size; // 元数据页大小
uint32_t num_md_pages; // 元数据页数量

// 元数据管理
struct spdk_bs_md_mask *used_clusters; // 已使用集群位图
struct spdk_bs_md_mask *used_pages; // 已使用页位图

// Blob 管理
struct spdk_blob *open_blob[SPDK_BLOBSTORE_TYPE_LENGTH];
uint64_t next_blobid; // 下一个 Blob ID
};

// Blob 结构
struct spdk_blob {
struct spdk_blob_store *bs; // 所属的 blobstore
spdk_blob_id id; // Blob ID
spdk_blob_id parent_id; // 父 Blob ID(用于克隆)

// 可变数据(会持久化到磁盘)
struct spdk_blob_mut_data clean; // 干净副本(与磁盘一致)
struct spdk_blob_mut_data active; // 活动副本(当前状态)

uint64_t num_clusters; // 集群数量
uint64_t *clusters; // 集群 LBA 数组

enum spdk_blob_state state; // Blob 状态
uint32_t open_ref; // 打开引用计数
};

Blobstore 与 BDEV 的关系:

1
2
3
4
5
6
// Blobstore 通过 bdev 访问底层存储
struct spdk_bs_dev *spdk_bdev_create_bs_dev_from_desc(struct spdk_bdev_desc *desc);

// Blobstore 在 bdev 上初始化
int spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_blob_store_opts *opts,
spdk_bs_op_with_handle_complete cb_fn, void *cb_arg);

关键特性:

  • 持久化: 所有元数据都持久化到磁盘,支持恢复
  • 高性能: I/O 路径无锁,元数据和数据分离
  • 可扩展: 支持可变大小的 Blob,最大可达设备容量
  • 快照支持: 支持 Blob 快照和克隆

3.3 lvol (逻辑卷管理)

位置: lib/lvol/lvol.c

功能: lvol 是建立在 Blobstore 之上的逻辑卷管理系统,将 Blobstore 的 Blob 封装为逻辑卷(logical volume)。

核心职责:

  1. 逻辑卷存储(lvol store)管理

    • 在 bdev 上创建 Blobstore
    • 管理 lvol store 的生命周期
    • lvol store 的元数据管理
  2. 逻辑卷(lvol)管理

    • 创建、删除、打开、关闭逻辑卷
    • 每个逻辑卷对应 Blobstore 上的一个 Blob
    • 逻辑卷的快照和克隆
  3. BDEV 封装

    • 将逻辑卷封装为 BDEV 设备
    • 提供块设备接口给上层协议使用
    • I/O 请求的路由和处理

关键数据结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 逻辑卷存储结构
struct spdk_lvol_store {
char name[SPDK_LVS_NAME_MAX]; // 名称
struct spdk_blob_store *blobstore; // 底层的 Blobstore
struct spdk_bdev *bdev; // 底层块设备
struct spdk_bdev_desc *bdev_desc; // 块设备描述符

// 逻辑卷列表
TAILQ_HEAD(, spdk_lvol) lvols; // 逻辑卷链表

uint32_t cluster_sz; // 集群大小
uint64_t total_data_clusters; // 总数据集群数
uint64_t free_clusters; // 空闲集群数
};

// 逻辑卷结构
struct spdk_lvol {
char name[SPDK_LVOL_NAME_MAX]; // 名称
char unique_id[SPDK_LVOL_NAME_MAX]; // 唯一标识符

struct spdk_lvol_store *lvs; // 所属的 lvol store
struct spdk_blob *blob; // 对应的 Blob

struct spdk_bdev *bdev; // 对应的 BDEV 设备
uint32_t ref_count; // 引用计数

uint64_t size_in_bytes; // 大小(字节)
uint64_t num_clusters; // 集群数量

bool action_in_progress; // 是否有操作正在进行
};

lvol 与 Blobstore 的关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1. 创建 lvol store
spdk_lvs_init()
→ 在 bdev 上创建 Blobstore
→ 初始化 lvol store 元数据

2. 创建逻辑卷
spdk_lvol_create()
→ 在 Blobstore 上创建 Blob
→ 将 Blob 封装为 lvol
→ 创建对应的 BDEV 设备

3. 打开逻辑卷
spdk_lvol_open()
→ 打开对应的 Blob
→ 增加引用计数

4. I/O 操作
应用 → BDEV → lvol → Blob → Blobstore → bdev → NVMe Driver

关键功能:

  • 快照: 基于 Blob 快照实现
  • 克隆: 基于 Blob 克隆实现
  • 动态扩展: 逻辑卷可以动态扩展
  • 元数据持久化: 所有元数据都持久化到 Blobstore

3.4 NVMe BDEV 模块

位置: module/bdev/nvme/bdev_nvme.c

功能: 将 NVMe 控制器和命名空间封装为 BDEV 设备。

主要流程:

1
2
3
4
5
6
7
8
9
1. NVMe 控制器探测 (Probe)

2. NVMe 控制器附加 (Attach)

3. 命名空间识别 (Identify Namespace)

4. 创建 BDEV 设备

5. 注册到 BDEV 管理器

关键函数:

  • bdev_nvme_create(): 创建 NVMe BDEV
  • bdev_nvme_delete(): 删除 NVMe BDEV
  • nvme_bdev_create(): 从命名空间创建 BDEV
  • nvme_bdev_destruct(): 销毁 BDEV

3.3 NVMe 驱动层

位置: lib/nvme/nvme_ctrlr.c, lib/nvme/nvme_pcie.c

功能: 用户态 NVMe 驱动,管理 NVMe 控制器、命名空间和队列对。

主要组件:

3.3.1 NVMe 控制器管理

1
2
3
4
5
6
7
8
9
10
11
12
13
// 控制器结构
struct spdk_nvme_ctrlr {
struct spdk_nvme_transport_id trid; // 传输ID
struct spdk_nvme_ctrlr_opts opts; // 控制器选项

struct spdk_nvme_ns *ns[SPDK_NVME_MAX_NS]; // 命名空间数组
uint32_t num_ns; // 命名空间数量

struct spdk_nvme_qpair *adminq; // 管理队列
struct spdk_nvme_qpair **io_qpairs; // I/O 队列数组

struct nvme_async_event_request *aer_list; // 异步事件请求列表
};

关键流程:

  1. 探测阶段 (spdk_nvme_probe())

    • 扫描 PCI 总线或网络地址
    • 识别 NVMe 控制器
    • 调用用户回调函数
  2. 附加阶段 (spdk_nvme_ctrlr_attach())

    • 初始化控制器寄存器
    • 创建管理队列对 (Admin Queue Pair)
    • 识别控制器能力
    • 识别命名空间列表
  3. 命名空间识别 (nvme_ctrlr_identify_active_ns())

    • 获取活动命名空间列表
    • 对每个命名空间进行识别
    • 创建命名空间对象
  4. 队列对管理 (spdk_nvme_ctrlr_alloc_io_qpair())

    • 创建 I/O 队列对
    • 分配队列内存
    • 配置队列参数

3.3.2 传输层

SPDK 支持多种传输类型:

  • PCIe 传输 (nvme_pcie.c)

    • 直接访问 PCIe 设备
    • 使用 VFIO 或 UIO 绑定设备
    • MMIO 寄存器访问
  • RDMA 传输 (nvme_rdma.c)

    • 基于 InfiniBand 或 RoCE
    • 支持 NVMe over Fabrics
  • TCP 传输 (nvme_tcp.c)

    • 基于 TCP/IP 网络
    • NVMe/TCP 协议实现
  • FC 传输 (nvme_fc.c)

    • 光纤通道传输
    • NVMe over FC 协议

3.4 环境抽象层 (env_dpdk)

位置: lib/env_dpdk/

功能: 封装 DPDK 功能,为 SPDK 提供统一的环境接口。

主要功能:

  1. 内存管理 (memory.c)

    • 大页内存分配
    • NUMA 感知的内存分配
    • IOVA (IO Virtual Address) 管理
  2. 线程管理 (threads.c)

    • 逻辑核心 (lcore) 管理
    • 线程绑定
    • CPU 亲和性设置
  3. PCI 设备管理 (pci.c)

    • PCI 总线扫描
    • 设备发现和枚举
    • VFIO/UIO 绑定

4. 硬盘发现与管理流程

4.1 PCIe NVMe 设备发现流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
┌─────────────────────────────────────────────────────────────┐
│ 1. 系统初始化 │
│ spdk_env_init() │
│ └─> rte_eal_init() (DPDK EAL 初始化) │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 2. PCI 总线扫描 │
│ DPDK PCI 总线扫描 │
│ └─> 发现 NVMe 控制器 │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 3. NVMe 控制器探测 │
│ spdk_nvme_probe() │
│ ├─> 扫描 PCI 设备 │
│ ├─> 匹配 NVMe 设备 │
│ └─> 调用用户探测回调 │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 4. NVMe 控制器附加 │
│ nvme_ctrlr_attach() │
│ ├─> 初始化 PCIe 传输 │
│ ├─> 读取控制器寄存器 (CAP, VS) │
│ ├─> 创建管理队列对 (Admin Queue Pair) │
│ ├─> 识别控制器 (Identify Controller) │
│ └─> 识别命名空间 (Identify Namespaces) │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 5. 命名空间识别 │
│ nvme_ctrlr_identify_active_ns() │
│ ├─> 获取活动命名空间列表 │
│ └─> 对每个命名空间: │
│ ├─> Identify Namespace │
│ ├─> Identify Namespace Descriptor List │
│ └─> 创建 spdk_nvme_ns 对象 │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 6. 创建 BDEV 设备 │
│ bdev_nvme_create() │
│ ├─> 为每个命名空间创建 nvme_bdev │
│ ├─> 注册到 BDEV 管理器 │
│ └─> 触发设备就绪事件 │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 7. 设备可用 │
│ - BDEV 设备已注册 │
│ - 可以通过 RPC 或应用程序访问 │
└─────────────────────────────────────────────────────────────┘

4.2 NVMe over Fabrics 设备发现流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌─────────────────────────────────────────────────────────────┐
│ 1. 配置传输ID │
│ 指定 trtype (RDMA/TCP/FC) │
│ 指定 traddr (目标地址) │
│ 指定 trsvcid (端口号) │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 2. 网络连接建立 │
│ - RDMA: 建立 QP (Queue Pair) │
│ - TCP: 建立 TCP 连接 │
│ - FC: 建立 FC 连接 │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 3. NVMe over Fabrics 握手 │
│ - Fabric Connect 命令 │
│ - 获取控制器 ID │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 4. 后续流程同 PCIe │
│ (附加控制器 → 识别命名空间 → 创建 BDEV) │
└─────────────────────────────────────────────────────────────┘

4.3 热插拔支持

SPDK 支持设备热插拔,通过以下机制实现:

  1. 热插拔轮询 (bdev_nvme_set_hotplug())

    • 定期扫描 PCI 总线
    • 检测新设备或设备移除
    • 触发相应的回调函数
  2. 热插拔事件处理

    • 设备添加:执行探测和附加流程
    • 设备移除:清理资源和注销设备

5. I/O 路径

5.1 I/O 请求流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
应用程序

spdk_bdev_read/write()

BDEV 抽象层 (bdev.c)
├─> 创建 bdev_io 结构
├─> QoS 检查
├─> 路由到相应的 BDEV 模块
└─> 提交 I/O 请求

BDEV 模块 (如 bdev_nvme.c)
├─> 获取 NVMe 队列对
├─> 构建 NVMe 命令
└─> 提交到 NVMe 队列

NVMe 传输层 (如 nvme_pcie.c)
├─> 写入提交队列 (SQ)
├─> 更新门铃寄存器
└─> 轮询完成队列 (CQ)

硬件设备
├─> 执行 I/O 操作
└─> 写入完成队列

NVMe 传输层
├─> 检测完成队列更新
├─> 处理完成事件
└─> 调用完成回调

BDEV 模块
└─> 调用 bdev_io 完成回调

应用程序
└─> I/O 完成回调执行

5.2 轮询模式 I/O

SPDK 使用轮询模式而非中断模式:

1
2
3
4
5
6
7
8
9
10
// 典型的轮询 I/O 模式
while (!io_completed) {
// 提交 I/O
spdk_bdev_read();

// 轮询完成队列
while (pending_ios > 0) {
spdk_nvme_qpair_process_completions(qpair, 0);
}
}

优势:

  • 零中断延迟
  • 可预测的延迟
  • 更高的吞吐量

6. BDEV 模块注册机制

6.1 模块注册

每个 BDEV 模块通过以下方式注册:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 模块注册宏
SPDK_BDEV_MODULE_REGISTER(nvme, nvme_module_init, nvme_module_fini)

// 模块结构
struct spdk_bdev_module {
const char *name; // 模块名称

// 初始化回调
int (*module_init)(void);

// 退出回调
void (*module_fini)(void);

// 异步初始化回调
void (*async_init)(void);

// 异步退出回调
void (*async_fini)(void);

// 检查设备回调
void (*examine)(struct spdk_bdev *bdev);

// 获取配置回调
int (*config_json)(struct spdk_json_write_ctx *w);

TAILQ_ENTRY(spdk_bdev_module) tailq;
};

6.2 模块初始化顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
1. 静态模块列表构建
(通过 SPDK_BDEV_MODULE_REGISTER 宏)

2. 模块异步初始化阶段
- 调用每个模块的 async_init()
- 例如:NVMe 模块扫描 PCI 设备

3. 模块同步初始化阶段
- 调用每个模块的 module_init()

4. 设备检查阶段
- 调用每个模块的 examine()
- 模块可以创建或修改 BDEV 设备

7. 设备配置与管理

7.1 JSON-RPC 接口

SPDK 通过 JSON-RPC 提供设备管理接口:

主要 RPC 命令:

  • bdev_nvme_attach_controller: 附加 NVMe 控制器
  • bdev_nvme_detach_controller: 分离 NVMe 控制器
  • bdev_nvme_get_controllers: 获取控制器列表
  • bdev_get_bdevs: 获取所有 BDEV 设备列表
  • bdev_get_bdevs: 获取 BDEV 统计信息

7.2 配置文件

SPDK 支持通过配置文件定义设备:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"subsystems": [
{
"subsystem": "bdev",
"config": [
{
"method": "bdev_nvme_attach_controller",
"params": {
"name": "Nvme0",
"trtype": "PCIe",
"traddr": "0000:01:00.0"
}
}
]
}
]
}

8. 性能优化特性

8.1 零拷贝

  • 直接内存访问 (DMA)
  • 避免不必要的内存拷贝
  • 使用大页内存减少 TLB 缺失

8.2 NUMA 感知

  • 内存分配考虑 NUMA 节点
  • CPU 核心绑定到 NUMA 节点
  • 减少跨 NUMA 访问

8.3 无锁设计

  • 每核心数据结构
  • 无锁队列
  • 减少锁竞争

8.4 I/O 批处理

  • 批量提交 I/O 请求
  • 减少系统调用开销
  • 提高吞吐量

9. Blobstore + lvol 完整工作流程

9.1 初始化流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
┌─────────────────────────────────────────────────────────────┐
│ 1. 发现 NVMe 设备 │
│ NVMe Driver 扫描 PCI 总线 │
│ 发现 NVMe SSD │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 2. 创建 NVMe BDEV │
│ bdev_nvme_create() │
│ 将 NVMe 命名空间封装为 BDEV │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 3. 创建 Blobstore (可选) │
│ spdk_lvs_init() │
│ → spdk_bs_init() 在 BDEV 上创建 Blobstore │
│ → 初始化超级块和元数据区域 │
│ → 创建逻辑卷存储 (lvol store) │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 4. 创建逻辑卷 (可选) │
│ spdk_lvol_create() │
│ → 在 Blobstore 上创建 Blob │
│ → 将 Blob 封装为逻辑卷 (lvol) │
│ → 创建 lvol BDEV 设备 │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 5. 上层协议使用 │
│ NVMe-oF / iSCSI / vhost 等协议使用 lvol BDEV │
└─────────────────────────────────────────────────────────────┘

9.2 I/O 请求流程(使用 Blobstore + lvol)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
应用层发起 I/O 请求

spdk_bdev_read/write() (通过 lvol BDEV)

lvol 模块 (lib/lvol/lvol.c)
├─> 将 BDEV I/O 转换为 Blob I/O
└─> 调用 Blobstore I/O 接口

Blobstore (lib/blob/blobstore.c)
├─> 元数据查找:LBA → Cluster 映射
├─> Cluster 查找:Cluster ID → 物理 LBA
└─> 转换为底层 BDEV I/O

BDEV 抽象层 (lib/bdev/bdev.c)
└─> 路由到 NVMe BDEV 模块

NVMe BDEV 模块 (module/bdev/nvme/bdev_nvme.c)
├─> 获取 NVMe 队列对
├─> 构建 NVMe 命令
└─> 提交到 NVMe 队列

NVMe Driver (lib/nvme/nvme_pcie.c)
├─> 写入提交队列 (SQ)
├─> 更新门铃寄存器
└─> 轮询完成队列 (CQ)

NVMe SSD 硬件
├─> 执行 I/O 操作
└─> 写入完成队列

9.3 元数据管理流程

Blobstore 元数据组织:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
设备布局:
┌─────────────────────────────────────────────────────────┐
│ 超级块 (Super Block) │
│ - Blobstore 标识 │
│ - 版本信息 │
│ - 集群大小 │
│ - 元数据页数量 │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 元数据区域 (Metadata Pages) │
│ - 集群使用位图 │
│ - 元数据页使用位图 │
│ - Blob 元数据页 │
│ - Blob ID │
│ - 父 Blob ID │
│ - Cluster 列表 (LBA 数组) │
│ - 扩展属性 │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 数据区域 (Data Clusters) │
│ - Cluster 0 (1MB) │
│ - Cluster 1 (1MB) │
│ - ... │
└─────────────────────────────────────────────────────────┘

元数据操作流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1. 创建 Blob
spdk_blob_create()
→ 分配 Blob ID
→ 分配元数据页
→ 初始化 Blob 元数据
→ 同步元数据到磁盘

2. 写入数据
spdk_blob_write()
→ 查找或分配 Cluster
→ 更新 Cluster 映射表
→ 执行数据写入
→ 同步元数据(如果需要)

3. 读取数据
spdk_blob_read()
→ 查找 Cluster 映射
→ 执行数据读取

9.4 快照和克隆流程

基于 Blobstore 的快照:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1. 创建快照
spdk_lvol_create_snapshot()
→ spdk_blob_clone()
→ 在 Blobstore 上克隆 Blob
→ 创建新的 Blob ID
→ 共享父 Blob 的 Cluster(Copy-on-Write)
→ 创建新的 lvol

2. 写入快照
如果 Cluster 被共享:
→ 分配新的 Cluster
→ 复制旧数据到新 Cluster
→ 更新快照的 Cluster 映射
→ 执行写入操作

10. 总结

SPDK 的硬盘管理架构通过多层抽象实现了:

  1. 统一接口: BDEV 抽象层提供统一的块设备接口

  2. Blobstore 是核心: Blobstore 是真正的磁盘空间管理核心,负责:

    • 磁盘空间的分配和回收
    • 元数据的持久化和管理
    • Blob 对象的生命周期管理
  3. lvol 提供高级功能: 逻辑卷管理基于 Blobstore,提供:

    • 快照和克隆
    • 动态扩展
    • 元数据持久化
  4. 模块化设计: 不同类型的存储设备通过模块化方式管理

  5. 高性能: 用户态驱动、轮询模式、零拷贝等技术实现高性能

  6. 灵活性: 支持多种传输类型(PCIe、RDMA、TCP、FC)

  7. 可扩展性: 易于添加新的 BDEV 模块

核心架构路径:

1
2
3
4
5
6
7
8
9
10
11
NVMe SSD

NVMe Driver (用户态,轮询模式)

bdev (统一块设备抽象层)

Blobstore (真正的磁盘空间管理核心) ⭐

lvol (逻辑卷管理)

上层协议 (NVMe-oF / iSCSI / vhost / 应用)

这种架构使得 SPDK 能够高效管理各种类型的存储设备,为上层应用提供高性能的存储服务。Blobstore 作为磁盘空间管理的核心,为逻辑卷管理等高级功能提供了坚实的基础。

文章互动

阅读 --

留言

0 条留言

正在加载留言…