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 (物理硬件)
|
关键要点:
Blobstore 是核心:Blobstore 是真正的磁盘空间管理核心,负责:
- 磁盘空间的分配和回收
- 元数据的持久化和管理
- Blob(可变大小对象)的生命周期管理
- Cluster(存储单元)的分配
lvol 基于 Blobstore:逻辑卷(lvol)是建立在 Blobstore 之上的高级抽象:
- 每个逻辑卷对应 Blobstore 上的一个 Blob
- 提供快照、克隆等高级功能
- 提供块设备接口给上层协议使用
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 的块设备抽象层核心,提供统一的块设备接口。
主要职责:
设备管理
- 设备的注册和注销
- 设备查询和枚举
- 设备生命周期管理
I/O 管理
- I/O 请求的路由和分发
- I/O 缓冲区的分配和管理
- I/O 完成回调处理
QoS 控制
- I/O 速率限制(IOPS、带宽)
- 读写分离的速率控制
- 时间片(timeslice)机制
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
| struct spdk_bdev_mgr { struct spdk_mempool *bdev_io_pool; struct spdk_mempool *buf_small_pool; struct spdk_mempool *buf_large_pool; void *zero_buffer; TAILQ_HEAD(, spdk_bdev_module) bdev_modules; struct spdk_bdev_list bdevs; bool init_complete; pthread_mutex_t mutex; };
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; struct spdk_bdev_qos *qos; TAILQ_ENTRY(spdk_bdev) link; };
|
3.2 Blobstore (真正的磁盘空间管理核心) ⭐
位置: lib/blob/blobstore.c
功能: Blobstore 是 SPDK 中真正的磁盘空间管理核心,负责磁盘空间的分配、回收和元数据管理。
核心职责:
磁盘空间管理
- Cluster(存储单元,默认 1MB)的分配和回收
- 空闲空间的管理和跟踪
- 空间碎片整理
元数据管理
- 元数据的持久化(存储在设备上)
- 元数据页(Page)的管理
- 元数据的同步和恢复
Blob 对象管理
- Blob(可变大小对象)的创建、删除、打开、关闭
- Blob 数据的读、写、擦除操作
- Blob 快照和克隆支持
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
| struct spdk_blob_store { struct spdk_bs_dev *dev; uint64_t total_clusters; uint64_t free_clusters; uint32_t cluster_sz; uint32_t page_size; uint32_t num_md_pages; struct spdk_bs_md_mask *used_clusters; struct spdk_bs_md_mask *used_pages; struct spdk_blob *open_blob[SPDK_BLOBSTORE_TYPE_LENGTH]; uint64_t next_blobid; };
struct spdk_blob { struct spdk_blob_store *bs; spdk_blob_id id; spdk_blob_id parent_id; struct spdk_blob_mut_data clean; struct spdk_blob_mut_data active; uint64_t num_clusters; uint64_t *clusters; enum spdk_blob_state state; uint32_t open_ref; };
|
Blobstore 与 BDEV 的关系:
1 2 3 4 5 6
| struct spdk_bs_dev *spdk_bdev_create_bs_dev_from_desc(struct spdk_bdev_desc *desc);
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)。
核心职责:
逻辑卷存储(lvol store)管理
- 在 bdev 上创建 Blobstore
- 管理 lvol store 的生命周期
- lvol store 的元数据管理
逻辑卷(lvol)管理
- 创建、删除、打开、关闭逻辑卷
- 每个逻辑卷对应 Blobstore 上的一个 Blob
- 逻辑卷的快照和克隆
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; 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; struct spdk_blob *blob; struct spdk_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; 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; struct nvme_async_event_request *aer_list; };
|
关键流程:
探测阶段 (spdk_nvme_probe())
- 扫描 PCI 总线或网络地址
- 识别 NVMe 控制器
- 调用用户回调函数
附加阶段 (spdk_nvme_ctrlr_attach())
- 初始化控制器寄存器
- 创建管理队列对 (Admin Queue Pair)
- 识别控制器能力
- 识别命名空间列表
命名空间识别 (nvme_ctrlr_identify_active_ns())
- 获取活动命名空间列表
- 对每个命名空间进行识别
- 创建命名空间对象
队列对管理 (spdk_nvme_ctrlr_alloc_io_qpair())
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)
3.4 环境抽象层 (env_dpdk)
位置: lib/env_dpdk/
功能: 封装 DPDK 功能,为 SPDK 提供统一的环境接口。
主要功能:
内存管理 (memory.c)
- 大页内存分配
- NUMA 感知的内存分配
- IOVA (IO Virtual Address) 管理
线程管理 (threads.c)
- 逻辑核心 (lcore) 管理
- 线程绑定
- CPU 亲和性设置
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 支持设备热插拔,通过以下机制实现:
热插拔轮询 (bdev_nvme_set_hotplug())
- 定期扫描 PCI 总线
- 检测新设备或设备移除
- 触发相应的回调函数
热插拔事件处理
- 设备添加:执行探测和附加流程
- 设备移除:清理资源和注销设备
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
| while (!io_completed) { 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 的硬盘管理架构通过多层抽象实现了:
统一接口: BDEV 抽象层提供统一的块设备接口
Blobstore 是核心: Blobstore 是真正的磁盘空间管理核心,负责:
- 磁盘空间的分配和回收
- 元数据的持久化和管理
- Blob 对象的生命周期管理
lvol 提供高级功能: 逻辑卷管理基于 Blobstore,提供:
模块化设计: 不同类型的存储设备通过模块化方式管理
高性能: 用户态驱动、轮询模式、零拷贝等技术实现高性能
灵活性: 支持多种传输类型(PCIe、RDMA、TCP、FC)
可扩展性: 易于添加新的 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 作为磁盘空间管理的核心,为逻辑卷管理等高级功能提供了坚实的基础。
正在加载留言…