记录 SPDK NVMe over RDMA 的部署过程。
环境准备
- Ubuntu 22.04 虚拟机 x2
- dev1,作为 Host 端,ip:192.168.246.129
- dev2,作为 Target 端,ip:192.168.246.130
- dev2 可以在 dev1 环境准备完成后进行 clone
- 2 块虚拟硬盘:
- SATA:用于安装 Ubuntu
- NVMe:用于绑定 spdk
NVMe 硬盘不需要挂载和格式化,
lsblk
结果如下:
文件准备
需要下载的文件:(严格控制版本,不同版本可能会导致很多错误)
- spdk-24.05.x.zip
- isa-l_crypto-08297dc3e76d65e1bad83a9c9f9e49059cf806b5.zip
- libvfio-user-a646db0b7d65c774a0b9415ea582735e7c2d2eb6.zip
- dpdk-08f3a46de70afff49f55d175de690b5ad7e4a44d.zip
- xnvme-3834fd860d40b6a3608aae11f9ceb017a0c93b29.zip
- ocf-d1d6d7cb5f55b616d2aa5123f84ce4ece10fdb0b.zip
- isa-l-6f420b14a1e3e091bc9d15f508a54f82c007483c.zip
- intel-ipsec-mb-935a3802883249ba3b12e566833994af7991e808.zip
安装与构建
clone 项目源码
# pwd: ~/Workspace/spdk-24.05.x
# clone 源码
git clone -b v24.05.x git@github.com:spdk/spdk.git
# 或者直接下载 zip 文件(推荐)
# spdk-24.05.x.zip
更新子模块
# 更新子模块
git submodule update --init
# 建议手动 clone 子模块(网络原因)
# 1. 根据 Github repo 中 spdk 版本对应的 submodule 版本,
# 下载对应 zip 文件(严格控制版本一致)
# dpdk-08f3a46de70afff49f55d175de690b5ad7e4a44d.zip
# intel-ipsec-mb-935a3802883249ba3b12e566833994af7991e808.zip
# isa-l-6f420b14a1e3e091bc9d15f508a54f82c007483c.zip
# isa-l_crypto-08297dc3e76d65e1bad83a9c9f9e49059cf806b5.zip
# libvfio-user-a646db0b7d65c774a0b9415ea582735e7c2d2eb6.zip
# ocf-d1d6d7cb5f55b616d2aa5123f84ce4ece10fdb0b.zip
# xnvme-3834fd860d40b6a3608aae11f9ceb017a0c93b29.zip
# 2. 解压后文件夹名删掉 '-xxx' 字符串,
# 并把它们复制到 spdk 根目录下
# spdk/dpdk
# spdk/intel-ipsec-mb
# spdk/isa-l
# spdk/isa-l-crypto
# spdk/libvfio-user
# spdk/ocf
# spdk/xnvme
安装依赖
# 安装各种依赖包
# -r: 带 RDMA
sudo ./scripts/pkgdep.sh -r
# 出于网络原因,可以修改 sh 脚本,添加临时源
# scripts/pkgdep/ubuntu.sh 下:
pip3 install ninja -i https://pypi.doubanio.com/simple
pip3 install meson -i https://pypi.doubanio.com/simple
pip3 install pyelftools -i https://pypi.doubanio.com/simple
pip3 install ijson -i https://pypi.doubanio.com/simple
pip3 install python-magic -i https://pypi.doubanio.com/simple
pip3 install grpcio -i https://pypi.doubanio.com/simple
pip3 install grpcio-tools -i https://pypi.doubanio.com/simple
pip3 install pyyaml -i https://pypi.doubanio.com/simple
pip3 install Jinja2 -i https://pypi.doubanio.com/simple
pip3 install tabulate -i https://pypi.doubanio.com/simple
打上 patch、修改代码
开发者说明 master
分支已经整合该 patch
,v24.05.x
还未整合。
位于 lib/log/log.c
。添加和修改以下代码(共 3 处):
// lib/log.log.c
void spdk_vlog(enum spdk_log_level level, const char *file, const int line, const char *func,
const char *format, va_list ap)
{
int severity = LOG_INFO;
char *buf, _buf[MAX_TMPBUF], *ext_buf = NULL;
char timestamp[64];
va_list ap_copy; // 添加代码
int rc;
if (g_log) {
g_log(level, file, line, func, format, ap);
return;
}
if (level > g_spdk_log_print_level && level > g_spdk_log_level) {
return;
}
severity = spdk_log_to_syslog_level(level);
if (severity < 0) {
return;
}
buf = _buf;
va_copy(ap_copy, ap); // 添加代码
rc = vsnprintf(_buf, sizeof(_buf), format, ap);
if (rc > MAX_TMPBUF) {
/* The output including the terminating was more than MAX_TMPBUF bytes.
* Try allocating memory large enough to hold the output.
*/
rc = vasprintf(&ext_buf, format, ap_copy); // 修改代码:ap -> ap_copy
if (rc < 0) {
/* Failed to allocate memory. Allow output to be truncated. */
} else {
buf = ext_buf;
}
}
if (level <= g_spdk_log_print_level) {
get_timestamp_prefix(timestamp, sizeof(timestamp));
if (file) {
// ......
构建项目
执行单元测试
./test/unit/unittest.sh
# 正确结果:
# =====================
# All unit tests passed
# =====================
# WARN: lcov not installed or SPDK built without coverage!
# WARN: neither valgrind nor ASAN is enabled!
绑定 NVMe 设备
绑定 NVMe 设备:
./scripts/setup.sh
# 正确结果:
# 0000:0b:00.0 (15ad 07f0): nvme -> uio_pci_generic
# 查看状态
./scripts/setup.sh status
# 正确结果:
# Type BDF Vendor Device NUMA Driver Device Block devices
# NVMe 0000:0b:00.0 15ad 07f0 unknown uio_pci_generic - -
则绑定成功。lsblk
中看不到 NVMe 设备。
若输出结果为:
且运行 build/examples/hello_world
,若出现以下结果:
说明没有 NVMe 设备或者 NVMe 设备处于挂载状态,无法解除内核驱动,此时需要将该设备初始化或者其他的方法。
添加 NVMe 设备后,NVMe 设备不能处于挂载状态,lsblk
结果:
# lsblk
# ...
sda 8:0 0 60G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 513M 0 part /boot/efi
└─sda3 8:3 0 59.5G 0 part /var/snap/firefox common/host-hunspell
/
nvme0n1 259:0 0 50G 0 disk
再次绑定后测试,出现正确结果则成功。
取消绑定
部署 RDMA Soft-RoCE
参考 【学习笔记】NVMeoF(二):NVMe over RDMA 环境部署 部署 RDMA 部分,部署好 RDMA Soft RoCE 软件栈。
仅部署 RDMA 部分,sh 脚本中从 # 1. config nvme subsystem
后的代码全部注释掉。
重启后需要重新部署一遍 RDMA 软件栈。
这部分结束可以对 dev1 进行克隆。
配置 SPDK NVMe over RDMA Target 端
Target 端 ip:192.168.246.130
。
运行 nvmeof-setup.sh 脚本部署 RDMA Soft-RoCE
绑定 NVMe SSD 设备
./scripts/setup.sh
# 正确结果:
# 0000:0b:00.0 (15ad 07f0): nvme -> uio_pci_generic
# 查看状态
./scripts/setup.sh status
# 正确结果:
# Type BDF Vendor Device NUMA Driver Device Block devices
# NVMe 0000:0b:00.0 15ad 07f0 unknown uio_pci_generic - -
这个 BDF 0000:0b:00.0
可能会变化,需要记住。
给 SPDK 分配大页(非必须)
echo 32768 | tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
# output:
# 32768
mkdir /dev/hugepages_2mb
mount -t hugetlbfs none /dev/hugepages_2mb -o pagesize=2MB
启动 tgt 并监听
# 具体参数代表含义还没完全弄清,可以通过 --help 查询
# 1. 启动 nvmf_tgt 并监听
# 这里第一次可能没能启动成功,再试一次看到 succeed 就是成功
build/bin/nvmf_tgt & scripts/rpc.py nvmf_create_transport -t RDMA -u 8192 -i 131072 -c 8192
# 2. 将 NVMe 控制器附加到 SPDK 的块设备层
# 0000:0b:00.0 是上文的 BDF
./scripts/rpc.py bdev_nvme_attach_controller -b NVMe1 -t PCIe -a 0000:0b:00.0
# output:
# NVMe1n1
# 3. 创建 subsystem
# cnode1、SPDK00000000000001 可以自定义
./scripts/rpc.py nvmf_create_subsystem nqn.2016-06.io.spdk:cnode1 -a -s SPDK00000000000001 -d SPDK_Controller1
# 4. 添加 namespace
./scripts/rpc.py nvmf_subsystem_add_ns nqn.2016-06.io.spdk:cnode1 NVMe1n1
# NVMe1n1 是 2 中的输出
# 5. 添加监听
# -a 是本机 ip,-s 是端口,可修改
./scripts/rpc.py nvmf_subsystem_add_listener nqn.2016-06.io.spdk:cnode1 -t rdma -a 192.168.246.130 -s 4420
# 6. 再添加 namespace
再加一个ns
./scripts/rpc.py bdev_nvme_attach_controller -b NVMe2 -t PCIe -a 0000:0b:00.0
# outout:
# NVMe2n1
./scripts/rpc.py nvmf_subsystem_add_ns nqn.2016-06.io.spdk:cnode1 NVMe2n1
# 获取 subsystem 信息
./scripts/rpc.py nvmf_get_subsystems
# 删除 subsystem
./scripts/rpc.py nvmf_delete_subsystem nqn.2016-06.io.spdk:cnode1
# 删除 ns
# ns_id 通过 nvmf_get_subsystems 获取
./scripts/rpc.py nvmf_remove_ns <nsid>
# 移除监听
./scripts/rpc.py nvmf_subsystem_remove_listener nqn.2016-06.io.spdk:cnode1 -t rdma -a 192.168.246.130 -s 4420
配置 SPDK NVMe over RDMA Host 端
Host 端 ip:192.168.246.129
。
运行 nvmeof-setup.sh 脚本部署 RDMA Soft-RoCE
SPDK 初始化
发现 Target 并连接(与 SPDK 无关)
这一步执行的是 nvme-cli
的命令,需要经过 kernel 驱动,而 SPDK 是用户态驱动。可以直接跳过这一步直接运行 SPDK 的应用程序。
# 发现
nvme discover -t rdma -a 192.168.246.130 -s 4420
# output:
# =====Discovery Log Entry 0======
# trtype: rdma
# adrfam: ipv4
# subtype: nvme subsystem
# treq: not required
# portid: 0
# trsvcid: 4420
# subnqn: nqn.2016-06.io.spdk:cnode1
# traddr: 192.168.246.130
# rdma_prtype: not specified
# rdma_qptype: connected
# rdma_cms: rdma-cm
# rdma_pkey: 0x0000
# 连接
nvme connect -t rdma -n "nqn.2016-06.io.spdk:cnode1" -a 192.168.246.130 -s 4420
# 查看设备
nvme list
lsblk
# 都可以看到连接的 nvme 设备
简单测试
# 用 spdk 自带的 perf 进行测试
./build/bin/spdk_nvme_perf -r 'trtype:rdma adrfam:IPv4 traddr:192.168.246.130 trsvcid:4420' -q 256 -o 4096 -w randread -t 100
# 一些参数含义
# -q, --io-depth <val> io depth
# -o, --io-size <val> io size in bytes
# -w, --io-pattern <pattern> io pattern type, must be one of:
# (read, write, randread, randwrite, rw, randrw)
# -t, --time <sec> time in seconds
# -r, --transport <fmt> Transport ID for local PCIe NVMe or NVMeoF
# 对于同时测试多块盘,只需要添加多个 -r 指定设备地址即可
# output:
# ===== spdk_nvme_perf start =====
# Initializing NVMe Controllers
# Attached to NVMe over Fabrics controller at 192.168.246.130:4420: nqn.2016-06.io.spdk:cnode1
# Controller IO queue size 128, less than required.
# Consider using lower queue depth or smaller IO size, because IO requests may be queued at the NVMe driver.
# Associating RDMA (addr:192.168.246.130 subnqn:nqn.2016-06.io.spdk:cnode1) NSID 1 with lcore 0
# Initialization complete. Launching workers.
# ========================================================
# Latency(us)
#Device Information : IOPS MiB/s Average min max
#RDMA (addr:192.168.246.130 subnqn:nqn.2016-06.io.spdk:cnode1) NSID 1 from core 0: 6091.58 23.80 42033.57 3583.64 87966.63
#========================================================
#Total : 6091.58 23.80 42033.57 3583.64 87966.63
测试结果图:
这里测试结果的值较低,可能是因为虚拟机的缘故?
取消连接(与 SPDK 无关)
如果执行了前面的 nvme connect
命令连接设备,则这里执行 nvme disconnect
命令取消连接。