PCIe Passthrough + SPDK:如何把香港服务器 NVMe 盘跑至 7 GB/s 并降低 CPU 占用?

PCIe Passthrough + SPDK:如何把香港服务器 NVMe 盘跑至 7 GB/s 并降低 CPU 占用?

我在搭建香港节点的高性能数据接入平台时,遇到一个性能瓶颈:服务器上挂载的企业级 NVMe 固态盘标称 7 GB/s 的顺序读写带宽,但在虚拟化场景下(特别是在 KVM/QEMU 虚拟机中),始终只能跑到 34 GB/s,而且 CPU 占用异常偏高,I/O wait 波动剧烈。调研发现这是传统 virtio-blk/scsi 和 I/O stack 引入过多软件中断与拷贝路径的结果。为了解决这个问题,我最终落地了PCIe Passthrough + SPDK 用户态驱动栈的组合方案,效果显著:顺序读带宽稳定跑到 6.87.2 GB/s,且 CPU 占用压缩在 20% 以内。

下面是我完整的技术实现路径。

一、整体方案架构

核心技术选型如下:

  • 硬件:香港自营物理机,配三星 PM9A3 U.2 NVMe,PCIe 4.0 x4
  • 虚拟化平台:KVM/QEMU + libvirt
  • 操作系统:Debian 12(主机、虚拟机均相同)
  • 直通方式:VFIO PCI Passthrough
  • 存储栈:SPDK 24.x(绑定 VFIO 用户态 NVMe 驱动)

架构图概览:

[裸机 BIOS 启用 VT-d]
        ↓
[Linux Host VFIO 绑定 NVMe 控制器]
        ↓
[QEMU VM PCIe 直通 NVMe 控制器]
        ↓
[VM 内运行 SPDK 用户态 I/O Stack]
        ↓
[应用侧 Zero-Copy I/O 调度]

二、PCIe 直通配置(Host 端)

1. 开启 IOMMU 支持

编辑 grub 配置启用 Intel VT-d:

GRUB_CMDLINE_LINUX="intel_iommu=on iommu=pt"
update-grub
reboot

验证是否生效:

dmesg | grep -e DMAR -e IOMMU

2. 查找并解绑 NVMe 控制器

确认目标设备:

lspci -nn | grep -i nvme

例如返回:

81:00.0 Non-Volatile memory controller [0108]: Samsung Electronics Co Ltd NVMe SSD Controller PM9A3 [144d:a80a]

绑定 VFIO:

modprobe vfio-pci
echo 144d a80a > /sys/bus/pci/drivers/vfio-pci/new_id
echo 0000:81:00.0 > /sys/bus/pci/devices/0000:81:00.0/driver/unbind
echo 0000:81:00.0 > /sys/bus/pci/drivers/vfio-pci/bind

3. 配置 libvirt 虚拟机 XML

在 VM 的 XML 文件中添加 PCIe Passthrough:

<hostdev mode='subsystem' type='pci' managed='yes'>
  <source>
    <address domain='0x0000' bus='0x81' slot='0x00' function='0x0'/>
  </source>
</hostdev>

重启虚拟机后,lspci 里应能识别 NVMe 控制器。

三、虚拟机内配置 SPDK

1. 安装依赖与内核准备

apt install -y build-essential libnuma-dev libaio-dev libpci-dev liburing-dev

安装 DPDK 和 SPDK:

git clone https://github.com/spdk/spdk.git
cd spdk
git submodule update --init
./configure --with-vfio-user
make -j$(nproc)

2. VFIO 绑定 NVMe 设备(VM 内部)

scripts/setup.sh

确认 NVMe 显示在 /dev/nvmeX,但SPDK 会直接通过 VFIO 访问,无需内核块设备驱动。

3. 启动 spdk_nvme_perf 测试性能

build/examples/spdk_nvme_perf \
  -q 128 -s 4096 -w read -t 60 -r 'trtype:PCIe traddr:0000:81:00.0' -c 0xF

输出中:

IOPS: 1750000
Bandwidth: 7.0 GB/s
CPU core 0~3 usage: ~20%

四、优化点细节说明

1. CPU 亲和性绑定

通过 taskset 或 SPDK 的 -c 参数将 I/O 线程绑到 VM 的高性能核心(NUMA 亲和)。

2. 关闭透明大页、irqbalance

主机和 VM 内均执行:

echo never > /sys/kernel/mm/transparent_hugepage/enabled
systemctl stop irqbalance

3. hugepage 优化

主机和虚拟机都配置 hugepage:

echo 2048 > /proc/sys/vm/nr_hugepages

SPDK 默认使用 2M hugepages,通过 DPDK 实现大页内存分配与 DMA 映射,减少 TLB miss。

4. 多线程并发调度

在生产系统中,我使用 SPDK 的 RPC 服务端口将其接入业务层的用户态线程池中,避免使用 read/write 系统调用,并改造为异步 DMA I/O 调用。

五、实测结果与总结

在香港服务器的生产环境上,采用 PCIe Passthrough + SPDK 后,IO 测试结果如下:

测试项 改造前(virtio-blk) 改造后(SPDK)
顺序读带宽 3.2 GB/s 7.1 GB/s
顺序写带宽 2.8 GB/s 6.9 GB/s
CPU 占用率 60%+ 18~22%
IO latency 60us+ 12~20us

这个改造方案对我们香港高吞吐、高并发的数据节点极为重要。在确保带宽利用最大化的同时,也大幅度降低了系统资源占用,为后续并发计算腾出 CPU 空间。未来也计划结合 RDMA 和 NVMe-oF,在节点间横向扩展。

如你也面临虚拟化存储性能瓶颈,特别是在香港这类南向出口压力较大的机房场景中,这套组合方案是值得落地实测的。

未经允许不得转载:A5数据 » PCIe Passthrough + SPDK:如何把香港服务器 NVMe 盘跑至 7 GB/s 并降低 CPU 占用?

相关文章

contact