《闪存数据》第三部分:使用 TCP 的 NVMe over Fabrics

通过使用 TCP 的 NVMe over Fabrics 网络导出的远程 NVMe 块设备。

Linux 内核 5.0 版本带来了许多优秀的功能,其中之一是引入了通过原生 TCP 的 NVMe over Fabrics (NVMeoF)。如果您还记得,在本系列的前一部分(“闪存数据》第二部分:使用 NVMe 驱动器并创建 NVMe over Fabrics 网络”),我解释了如何通过一种称为融合以太网 RDMA (RoCE) 的方法在 RDMA(一种 Infiniband 协议)上启用您的 NVMe 网络。顾名思义,它允许在传统以太网上传输 RDMA。虽然这效果很好,但它引入了一些开销(以及延迟)。因此,当 5.0 内核引入对 NVMe 目标的原生 TCP 支持时,它简化了配置相同网络所需的方法或步骤,正如我在上一篇文章中所示,并且它还使访问远程 NVMe 驱动器更快。

软件需求

要继续本教程,您需要安装 5.0 或更高版本的 Linux 内核,并在您的发起端(导入远程 NVMe 卷的服务器)和目标端(导出其本地 NVMe 卷的服务器)的操作系统中构建并插入以下模块


# NVME Support
CONFIG_NVME_CORE=y
CONFIG_BLK_DEV_NVME=y
# CONFIG_NVME_MULTIPATH is not set
CONFIG_NVME_FABRICS=m
CONFIG_NVME_RDMA=m
# CONFIG_NVME_FC is not set
CONFIG_NVME_TCP=m
CONFIG_NVME_TARGET=m
CONFIG_NVME_TARGET_LOOP=m
CONFIG_NVME_TARGET_RDMA=m
# CONFIG_NVME_TARGET_FC is not set
CONFIG_NVME_TARGET_TCP=m

更具体地说,您需要导入远程 NVMe 卷的模块


CONFIG_NVME_TCP=m

以及导出本地 NVMe 卷的模块


CONFIG_NVME_TARGET_TCP=m

在继续之前,请确保您的物理(或虚拟)机是最新的。一旦您确认是这种情况,请确保您能够看到所有本地连接的 NVMe 设备(您将在网络上导出这些设备)


$ cat /proc/partitions |grep -e nvme -e major
major minor  #blocks  name
 259        0 3907018584 nvme2n1
 259        1 3907018584 nvme3n1
 259        2 3907018584 nvme0n1
 259        3 3907018584 nvme1n1

如果您没有看到任何连接的 NVMe 设备,请确保内核模块已加载


petros@ubu-nvme1:~$ lsmod|grep nvme
nvme                   32768  0
nvme_core              61440  1 nvme

以下模块需要在发起端加载


$ sudo modprobe nvme
$ sudo modprobe nvme-tcp

并且,以下模块需要在目标端加载


$ sudo modprobe nvmet
$ sudo modprobe nvmet-tcp

接下来,您将安装名为 nvme-cli 的驱动器管理实用程序。此实用程序由定义 NVMe 规范的 NVM Express 委员会定义和维护。您可以在 此处 找到托管源代码的 GitHub 存储库。需要最近的版本。从 GitHub 存储库克隆源代码。构建并安装它


$ make
$ make install

通过 TCP 在网络上访问驱动器

本节的目的是利用高速 SSD 技术并将其扩展到本地服务器之外。NVMe 不必局限于物理插入它的服务器。在本示例中,为了方便起见,我使用两台虚拟机来创建此网络。这样做绝对没有任何优势,除非您只是想进行练习,否则我不建议您这样做。实际上,您应该仅在连接了高速网卡的物理机上启用以下功能。无论如何,在目标虚拟机中,我连接了几个低容量的虚拟 NVMe 驱动器(每个 2GB)


$ sudo nvme list
Node           SN             Model                  Namespace
-------------- -------------- ---------------------- ---------
/dev/nvme0n1   VB1234-56789   ORCL-VBOX-NVME-VER12     1
/dev/nvme0n2   VB1234-56789   ORCL-VBOX-NVME-VER12     2

Usage                      Format           FW Rev
-------------------------- ---------------- --------
2.15  GB /   2.15  GB      512   B +  0 B   1.0
2.15  GB /   2.15  GB      512   B +  0 B   1.0

[注意:上面的表格输出已修改以提高可读性。]

以下说明严重依赖于 sysfs 虚拟文件系统。理论上,您可以使用开源实用程序 nvmet-cli 导出 NVMe 目标,它可以完成所有复杂的繁重工作。但是,那样有什么乐趣呢?

导出目标

挂载内核用户配置文件系统。这是必需的。所有 NVMe 目标指令都需要在此文件系统中提供的 NVMe 目标树


$ sudo /bin/mount -t configfs none /sys/kernel/config/

创建一个 NVMe 目标子系统来托管您的设备(要导出),然后进入其目录


$ sudo mkdir /sys/kernel/config/nvmet/subsystems/nvmet-test
$ cd /sys/kernel/config/nvmet/subsystems/nvmet-test

本示例将通过使新创建的子系统可供任何尝试连接到它的主机访问来简化主机连接。在生产环境中,您绝对应该将其锁定到特定主机的 NQN


$ echo 1 |sudo tee -a attr_allow_any_host > /dev/null

导出目标时,它是使用“唯一”的 NVMe 限定名 (NQN) 完成的。这个概念与 iSCSI 限定名 (IQN) 非常相似。此 NQN 使其他操作系统能够在可能托管多个 NVMe 设备的网络上导入和使用远程 NVMe 设备。

定义子系统命名空间并进入其目录


$ sudo mkdir namespaces/1
$ cd namespaces/1/

将本地 NVMe 设备设置为新创建的命名空间


$ echo -n /dev/nvme0n1 |sudo tee -a device_path > /dev/null

并启用命名空间


$ echo 1|sudo tee -a enable > /dev/null

现在,您将创建一个 NVMe 目标端口来导出新创建的子系统并进入其目录路径


$ sudo mkdir /sys/kernel/config/nvmet/ports/1
$ cd /sys/kernel/config/nvmet/ports/1

嗯,导出子系统时,您将使用首选以太网接口端口的 IP 地址(例如,eth0)


$ echo 192.168.1.92 |sudo tee -a addr_traddr > /dev/null

然后,您将设置一些其他参数


$ echo tcp|sudo tee -a addr_trtype > /dev/null
$ echo 4420|sudo tee -a addr_trsvcid > /dev/null
$ echo ipv4|sudo tee -a addr_adrfam > /dev/null

并创建一个软链接,以从新创建的端口指向子系统


$ sudo ln -s /sys/kernel/config/nvmet/subsystems/nvmet-test/
 ↪/sys/kernel/config/nvmet/ports/1/subsystems/nvmet-test

您现在应该在 dmesg 中看到以下消息


$ dmesg |grep "nvmet_tcp"
[24457.458325] nvmet_tcp: enabling port 1 (192.168.1.92:4420)

导入目标

主机当前没有 NVMe 设备


$ nvme list
Node      SN           Model                    Namespace
--------- ------------ ------------------------ ---------

Usage          Format           FW Rev
-------------- ---------------- --------

[注意:上面的表格输出已修改以提高可读性。]

扫描您的目标机器以查找任何导出的 NVMe 卷


$ sudo nvme discover -t tcp -a 192.168.1.92 -s 4420

Discovery Log Number of Records 1, Generation counter 1
=====Discovery Log Entry 0======
trtype:  tcp
adrfam:  ipv4
subtype: nvme subsystem
treq:    not specified, sq flow control disable supported
portid:  1
trsvcid: 4420
subnqn:  nvmet-test
traddr:  192.168.1.92
sectype: none

一定是您的幸运日。看起来目标机器正在导出一个或多个卷。您需要记住它的 subnqn 字段:nvmet-test。现在连接到 subnqn


$ sudo nvme connect -t tcp -n nvmet-test -a 192.168.1.92 -s 4420

如果您返回列出所有 NVMe 设备,您现在应该看到由该 subnqn 导出的所有设备


$ sudo nvme list
Node             SN                   Model
---------------- -------------------- ------------------------
/dev/nvme1n1     8e0999a558e17818     Linux


Namespace Usage                   Format           FW Rev
--------- ----------------------- ---------------- --------
1         2.15  GB /   2.15  GB   512   B +  0 B    5.0.0-3

[注意:上面的表格输出已修改以提高可读性。]

验证它也像您的其他块设备一样显示


$ cat /proc/partitions |grep nvme
 259        1    2097152 nvme1n1

您可以通过键入以下内容从目标设备断开连接


$ sudo nvme disconnect -d /dev/nvme1n1

总结

您已经拥有了——通过使用 TCP 的 NVMe over Fabrics 网络导出的远程 NVMe 块设备。现在您可以像读写任何其他本地连接的高性能块设备一样读写它。现在您可以无需额外开销即可通过 TCP 映射块设备这一事实应该并将加速该技术的采用。

资源

Petros Koutoupis,《Linux Journal》特约编辑,目前是 Cray 公司 Lustre 高性能文件系统部门的高级性能软件工程师。他也是 RapidDisk 项目的创建者和维护者。Petros 在数据存储行业工作了十多年,并帮助开创了当今广泛使用的许多技术。

加载 Disqus 评论