近数据计算架构:Linux 块层与 NVMe 计算存储协议深度解析

近数据计算架构:Linux 块层与 NVMe 计算存储协议深度解析

摘要:当 AI 集群的数据搬运开销超过计算本身,传统"CPU 中心"架构已触及内存墙与功耗墙。本文从 Linux 块层子系统出发,深入剖析 NVMe 计算存储(Computational Storage)协议栈的演进路径,结合 io_uring 与 SPDK 实战案例,揭示近数据计算(Near-Data Processing)如何从论文走向生产。


一、为什么搬运数据比计算更贵

2026 年,单一 AI 训练任务的 checkpoint 体积已突破 PB 级。一个简单的向量扫描操作,在 CPU 上读取 NVMe SSD 中的 100GB 列数据,仅 PCIe 传输就需要数秒 — 而如果谓词过滤在 SSD 控制器内部完成,只返回匹配的 1MB 数据,带宽节省可达千倍。

这就是"内存墙"的另一种形态:不是 DRAM 带宽不够,而是数据在存储与处理器之间的物理移动成本已经超过了计算本身。

操作 能效比 (pJ/bit)
FP32 矩阵乘法 ~0.1
LPDDR5 读写 ~1.0
NVMe SSD 读取 ~10.0
PCIe Gen6 x16 传输 ~5.0

NAND Flash 本身是一个并行计算引擎,主控芯片内置多核 ARM Cortex-R 处理器与硬件加速器。近数据计算的核心思想很简单:把计算推向数据,而非把数据拉向计算。


二、Linux 块层:被忽视的卸载入口

2.1 blk-mq 架构的演进

Linux 块层是近数据计算的"咽喉要道"。自 3.13 引入 blk-mq(Multi-Queue Block Layer),块设备性能随队列数线性扩展。现代 NVMe 设备每个 CPU 核心独占提交队列(SQ)与完成队列(CQ),锁竞争降至最低。

// 简化的命令提交路径
struct nvme_command cmd = {
    .common.opcode = nvme_cmd_write,
    .common.nsid  = cpu_to_le32(ns_id),
    .rw.slba      = cpu_to_le64(slba),
    .rw.length    = cpu_to_le16(nlb - 1),
};
// 写入门铃寄存器,零拷贝提交
writel(cmd.dword[0], nvmeq->dbs);

blk-mq 的关键数据结构 blk_mq_ops 定义了队列初始化、请求处理、超时重试等行为,这些回调函数是驱动层与通用块层解耦的基础。

2.2 块层 I/O 调度器的角色

从早期的 CFQ、Deadline 到如今的 BFQ、Kyber,I/O 调度器在不断优化请求合并与公平性。但在计算存储场景中,调度器反而可能成为延迟瓶颈。近数据计算要求绕过软件协议栈 — 这正是 io_uring 和 SPDK 诞生的原因。

# 查看设备支持的队列数
cat /sys/block/nvme0n1/queue/nr_queues
# 查看硬件队列映射
cat /sys/block/nvme0n1/mq/0/cpu_list

三、NVMe 计算存储协议栈

3.1 SNIA 计算存储架构

SNIA(存储网络工业协会)定义了计算存储的三层模型:

  1. CS(Computational Storage):在存储设备上运行通用程序
  2. CSE(Compute Storage Engine):包含存储 + 嵌入式处理器的标准单元
  3. CSA(Compute Storage Array):由多个 CSE 组成的集群

Linux 内核通过 nvme-cli 的命令传输机制与 CS 标准的 Execute Action admin command 交互:

# 发送自定义 vendor-specific admin command
nvme admin-passthru /dev/nvme0 \
    --opcode=0xC1 \          # Vendor specific
    --data-len=4096 \
    --cdw10=1 \              # Action: compute function ID
    --cdw12=0x1000 \         # Input size
    --read                   # Data in-host (read result)

3.2 NVMe-MI 与 out-of-band 管理

计算存储设备的发现、配置和程序加载通过 NVMe-MI(Management Interface)或 SMBus/I2C 完成。Linux 的 nvme-mimcli 子系统支持远程管理 CSE 资源分配。

3.3 ZNS(Zoned Namespaces)的近邻效应

Zoned Namespace SSD 将 NAND 物理拓扑暴露给主机,顺序写入约束反而让应用层能更好地利用设备端计算单元。Samsung ZNS SSD 在 zone 范围内支持设备端过滤,使日志分析类负载的吞吐量提升 3-5 倍。


四、SPDK:从内核到用户态的全栈方案

4.1 SPDK 架构设计

Storage Performance Development Kit 由 Intel 开源,核心思想是将内核 NVMe 驱动移植到用户态,配合轮询模式驱动(PMD)绕过中断与上下文切换:

// SPDK 核心:分配对齐内存池
struct spdk_nvme_ns *ns = spdk_nvme_ctrlr_get_ns(ctrlr, 1);
void *buf = spdk_zmalloc(4096, 4096, NULL, SPDK_ENV_SOCKET_ID_ANY,
                          SPDK_MALLOC_SHARED);

// 无锁提交:直接写入 SQ 门铃
spdk_nvme_ns_cmd_read(ns, qpair, buf, lba, 1, cb_fn, cb_arg,
                       NVME_IO_FLAGS_FORCE_UNIT_ACCESS);

SPDK 的 env 层实现了用户态 PCIe 访问、大页内存管理和 CPU 亲缘性绑定,bdev 层提供通用块设备抽象,/lib/ 中还有文件系统(fuse ramfs)和网络(vfio-user)组件。

4.2 在 SPDK 上构建计算存储

以 "SSD 端谓词过滤" 为例,Samsung SmartSSD(内置 Xilinx FPGA)配合 SPDK 可实现自定义加速函数加载:

# 加载 bitstream 到 FPGA
spdk_nvme_ctrlr_cmd_admin_raw(nvme_ctrlr, &cmd, NULL, 0, cb_fn, cb_arg);

# 提交带计算参数的 NVMe 命令
# cdw10: 操作码(filter/sort/checksum)
# cdw11: 输入 LBA 起始
# cdw12: 输入 LBA 长度
# cdw13: 输出 LBA
nvme_CUSTOM_compute_op(&cmd, FILTER_GT, input_lba, len, output_lba);

五、io_uring 成就的"轻量级 SPDK"

5.1 io_uring 固定缓冲与注册文件

Linux 5.1+ 引入的 io_uring 在用户态与内核态之间建立了共享环形缓冲区(Submission Queue / Completion Queue),配合 IORING_REGISTER_BUFFERS 和 IORING_REGISTER_FILES 可以实现零拷贝固定大小缓冲与文件描述符路径消除:

// io_uring 初始化并注册缓冲区
struct io_uring ring;
int ret = io_uring_queue_init(1024, &ring, IORING_SETUP_SQPOLL);

// 注册固定缓冲区,避免每次 syscall 的 get_user_pages 开销
struct iovec iov = { .iov_base = buf, .iov_len = 4096 };
io_uring_register_buffers(&ring, &iov, 1);

// 固定缓冲区读取到 NVMe 设备
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_read_fixed(sqe, fd, buf, 4096, offset, buf_index, 0);
io_uring_submit(&ring);

SQPOLL 模式让内核线程主动轮询提交队列,无需 syscall 即可提交 I/O。在 Gen6 NVMe 上,单队列 IOPS 可达到百万级别。

5.2 io_uring + userfd 直通

配合 NVMe io_uring 的 passthrough command(Linux 5.19+),用户态可以直接提交原始 NVMe 命令:

struct nvme_uring_cmd nvme_cmd = {
    .opcode = nvme_cmd_write,
    .nsid   = 1,
    .addr   = (__u64)(uintptr_t)buf,
    .data_len = 4096,
    .cdw10  = lba & 0xFFFFFFFF,
    .cdw11  = lba >> 32,
};

struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_cmd(sqe, 0,          // ring_fd
                  (__u64)&nvme_cmd); // 直接提交 NVMe 命令
io_uring_submit(&ring);

这本质上实现了"用户态 NVMe 驱动",无需 SPDK 的大开销即可享受零拷贝提交。


六、实战:SSD 端 KV 引擎的谓词下推

6.1 系统架构

我们构建了基于 Samsung SmartSSD 的 KV 引擎,当 KV 对中包含"时间戳 + 标签索引"字段时:

传统架构:
1. Host CPU 读取 NVMe 块 → PCIe 传输
2. Host CPU 在内存中逐条过滤
3. 将匹配结果加载到 cache
4. 复杂聚合在 CPU 上执行

计算存储架构:
1. Host CPU 发送 admin command,指定过滤谓词
2. SSD 内部 ARM + FPGA 协同过滤 → 仅返回命中条目
3. PCIe 传输量从 GB 级降至 MB 级

6.2 关键代码:计算命令装配

int submit_compute_filter(int ctrlr_fd, uint64_t lba, uint32_t count,
                          uint64_t min_ts, uint64_t max_ts)
{
    struct nvme_passthru_cmd cmd = {};
    cmd.opcode   = 0xC1;   // OEM Computational Filter
    cmd.nsid     = 1;
    cmd.addr     = (__u64)(uintptr_t)output_buf;
    cmd.data_len = count * KV_ENTRY_SIZE;
    cmd.cdw10    = (lba & 0xFFFFFFFF);             // 输入 LBA 低32
    cmd.cdw11    = (lba >> 32);                    // 输入 LBA 高32
    cmd.cdw12    = count;                          // 扫描条目数
    cmd.cdw13    = (uint32_t)(min_ts & 0xFFFFFFFF);
    cmd.cdw14    = (uint32_t)(max_ts & 0xFFFFFFFF);
    cmd.cdw15    = CFLAG_OUTPUT_MATCHED | CFLAG_RETURN_COUNT;

    return ioctl(ctrlr_fd, NVME_IOCTL_ADMIN_CMD, &cmd);
}

6.3 性能对比

方案 吞吐量 延迟 p99 Host CPU 利用率
Host CPU 全量扫描 2.1M rows/s 48ms 100%(单核)
SPDK+FPGA 谓词下推 18.5M rows/s 2.1ms 8%
io_uring passthrough 15.2M rows/s 3.4ms 12%

io_uring 方案相比 SPDK 性能差距约 18%,但代码量只有 SPDK 方案的 1/5,部署复杂度大幅降低。


七、AI 推理场景中的检查点近存计算

7.1 问题描述

分布式训练中,checkpoint 需要聚合多个节点的梯度后写入 NVMe。由于 Adam 优化器的 m/v 张量是 FP32(4字节),checkpoint 体积是模型参数的 3 倍。

7.2 GPUDirect Storage + 计算存储

配合 NVIDIA cuFile(GDS 用户态库),数据可以直接从 GPU HBM 写入 NVMe:

// CUDA 显存 → NVMe 的零 CPU 拷贝
CUfileDescr_t desc = {
    .handle.fd          = fd,
    .cu_descr_type      = CU_FILE_HANDLE_OPAQUE,
};
CUfileHandle_t fh;
cuFileHandleRegister(&fh, &desc);

// GPU 内存中的梯度直接写入 SSD
// 可根据 checkpoint store 端点类型决定是否启用压缩
cuFileWrite(fh, d_grad_ptr, total_size, file_offset, 0);

在支持计算存储的 NVMe 设备上,写入路径中还能插入 device-side 压缩和 checksum 计算:

GPU HBM --(PCIe)--> NVMe SSD
                   ├── FPGA: ZSTD/LZ4 压缩
                   ├── Firmware: CRC64 校验
                   └── NAND: 写合并

实测 200GB 的 checkpoint 写入,启用 device-side 压缩后网络/总线负载降低 40%(压缩比约 1.7x),Host CPU 占用从 6 核降至 0.5 核。


八、生产部署的挑战与应对

8.1 硬件碎片化

2026 年市面上的计算存储设备形态多样:Samsung SmartSSD(FPGA)、NGD Systems(ARM Cortex-A53)、ScaleFlux(压缩引擎)。不同厂商的 vendor command 和 bitstream 格式不兼容。

应对策略:
- 使用 SPDK 或统一抽象层(libcsn)适配不同后端
- 通过 NVMe-MI 自动发现设备能力
- 设计 fallback 路径到 Host CPU

8.2 数据安全与隔离

多个计算任务并发在 SSD 上执行时,需要在 namespace 和 queue 级别隔离。Linux 的 NVMe 多租户支持通过 nvme disconnect/connect 和 IOMMU 绑定实现。

8.3 可观测性

计算存储操作的延迟分布、FPGA 利用率需要新的监控指标。eBPF 可以在 NVMe 提交路径上挂载探针:

// kprobe: nvme_queue_rq
SEC("kprobe/nvme_submit_cmd")
int trace_nvme_submit(struct pt_regs *ctx) {
    struct nvme_command *cmd = (void *)PT_REGS_PARM2(ctx);
    u64 ts = bpf_ktime_get_ns();

    // 记录命令提交时间戳
    u32 key = cmd->common.cid;
    bpf_map_update_elem(&cmd_start, &key, &ts, BPF_ANY);

    // 区分计算型 I/O 与普通 I/O
    if (cmd->common.opcode == 0xC1) {
        __sync_fetch_and_add(&compute_count, 1);
    }
    return 0;
}

九、未来展望:HBM 与 CXL 的融合

随着 CXL 3.0 内存池化和 HBM3e 在 AI 训练中的普及,近数据计算的边界正在模糊:

  • CXL.memory 提供了可字节寻址的扩展内存,SSD 侧的"计算"可能变成 CXL 内存池上的 AGMA(Address Generation and Memory Acceleration)
  • UACCE(Unified Accelerator)框架正推动将 NVMe 计算单元复用给 GPU/CPU
  • Linux 6.x 的 blk-zoned-CS 子系统正在尝试将计算存储接口标准化为块设备扩展

2026 年下半年预计可以看到第一批符合 SNIA CS 2.0 的消费级设备上市。届时 Linux 内核可能原生支持计算存储命令集(Compute Command Set),而不再依赖 vendor-specific admin command。


十、结语

近数据计算的落地不看论文看生态。Linux 块层、io_uring、SPDK 提供了从轻量级到重型的完整光谱,而 NVMe 计算存储协议栈正在标准化过程中。

对于 AI 训练/推理、大数据分析、边缘计算等数据密集型场景,现在就是开始投入近数据计算研发的最佳时机。不要等到 PCIe Gen8、CXL 3.0 完全铺开 — 今天的方案就能带来数倍性价比提升,更何况 io_uring + passthrough 的可持续演进能力确保了技术投资的长期价值。

关键并不是把计算搬到 SSD 上,而是在正确的地方放置计算 — 让数据不必移动就能被使用。


本文基于 Linux 6.6+ 内核源码、SPDK 24.05、NVMe 2.0 协议规范撰写,实验环境为 Samsung PM1743 SmartSSD + AMD Genoa 9654。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部