闪存数据,第二部分:使用 NVMe 驱动器和创建 NVMe over Fabrics 网络

按照设计,NVMe 驱动器旨在为插入它们的机器提供本地访问;然而,NVMe over Fabric 规范旨在通过启用对同一设备的远程网络访问来解决这一限制。

本文将实践您在第一部分中学到的知识,并展示如何在 Linux 环境中使用 NVMe 驱动器。但是,在继续之前,您首先需要确保您的物理(或虚拟)机是最新的。一旦您确认了这一点,请确保您能够看到所有连接的 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

这些设备也会出现在 sysfs


$ ls /sys/block/|grep nvme
nvme0n1
nvme1n1
nvme2n1
nvme3n1

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


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

接下来,安装名为 nvme-cli 的驱动器管理实用程序。此实用程序由定义 NVMe 规范的 NVM Express 委员会定义和维护。nvme-cli 源代码托管在 GitHub 上。幸运的是,一些操作系统在其内部存储库中提供了此软件包。在最新的 Ubuntu 上安装它看起来像这样


petros@ubu-nvme1:~$ sudo add-apt-repository universe
petros@ubu-nvme1:~$ sudo apt update && sudo apt install
 ↪nvme-cli

使用此实用程序,您可以列出所有连接的 NVMe 驱动器的更多详细信息(注意:下面的表格输出已重新格式化和截断,以便更好地在此处显示)


$ sudo nvme list
Node      SN      Model     Namespace Usage   Format    FW Rev
--------------------------------------------------------------
/dev/nvme0n1  PHLF814001... Dell Express Flash NVMe P4500 4.0TB SFF  1
 ↪4.00  TB /   4.00  TB    512   B +  0 B   QDV1DP12
/dev/nvme1n1  PHLF814300... Dell Express Flash NVMe P4500 4.0TB SFF  1
 ↪4.00  TB /   4.00  TB    512   B +  0 B   QDV1DP12
/dev/nvme2n1  PHLF814504... Dell Express Flash NVMe P4500 4.0TB SFF  1
 ↪4.00  TB /   4.00  TB    512   B +  0 B   QDV1DP12
/dev/nvme3n1  PHLF814502... Dell Express Flash NVMe P4500 4.0TB SFF  1
 ↪4.00  TB /   4.00  TB    512   B +  0 B   QDV1DP12

注意:如果您没有物理 NVMe 驱动器连接到您的机器,但仍想(以有限的形式)继续学习,您可以在最新的 VirtualBox 虚拟化应用程序中安装和模拟 NVMe 控制器以及驱动器。

驱动器管理

在命令行上发出 nvme 命令会打印一个在线帮助菜单,其中包含完整的功能列表,其中一些功能可以定位和识别各种 NVMe 控制器、驱动器及其命名空间


list           List all NVMe devices and namespaces on machine
list-subsys    List nvme subsystems
id-ctrl        Send NVMe Identify Controller
id-ns          Send NVMe Identify Namespace, display structure
list-ns        Send NVMe Identify List, display structure

nvme-cli 实用程序的其他功能引入了命名空间管理


ns-descs      Send NVMe Namespace Descriptor List, display
 ↪structure
create-ns     Creates a namespace with the provided parameters
delete-ns     Deletes a namespace from the controller
attach-ns     Attaches a namespace to requested controller(s)
detach-ns     Detaches a namespace from requested controller(s)

命名空间是 NVMe 驱动器的独特功能。可以将它们视为物理设备的虚拟分区。命名空间是已定义的非易失性存储器量,可以格式化为逻辑块。配置后,一个或多个命名空间连接到控制器(或主机,有时是远程的)。每个命名空间可以支持各种块大小(例如 512 字节、4 KB 等)。定义后,它们将作为单独的块设备出现在主机上。

如果驱动器包含单个命名空间,则列出它将显示以下内容


$ nvme list-ns /dev/nvme0
[   0]:0x1

如果您开始创建更多命名空间,它将反映在列表中


$ sudo nvme list-ns /dev/nvme0
[   0]:0x1
[   1]:0x2

并在您的操作系统注册的块设备数量中再次反映


$ cat /proc/partitions |grep nvme0
 259        0    1953509292 nvme0n1
 259        1    1953509292 nvme0n2

使用相同的实用程序,您可以访问驱动器级别的日志记录


get-log       Generic NVMe get log, returns log in raw format
fw-log        Retrieve FW Log, show it
smart-log     Retrieve SMART Log, show it
error-log     Retrieve Error Log, show it
effects-log   Retrieve Command Effects Log, show it

您还可以设置驱动器级别的功能


get-feature     Get feature and show the resulting value
set-feature     Set a feature and show the resulting value
set-property    Set a property and show the resulting value

例如,假设您要启用 (1) 或禁用 (0) 驱动器的易失性写入缓存 (VWC)。您可以像这样列出其当前设置


$ sudo nvme id-ctrl /dev/nvme0|grep vwc
vwc     : 0

并像这样设置它


$ sudo nvme set-feature /dev/nvme0 -f 0x6 -v 1

您可以管理和更新驱动器固件


fw-commit    Verify and commit firmware to a specific slot
 ↪(fw-activate in old version < 1.2)
fw-download  Download new firmware

重置控制器(但不重置连接的驱动器)


reset           Resets the controller
subsystem-reset Resets the controller

发现并连接到网络上的其他 NVMe 设备(见下文)


discover        Discover NVMeoF subsystems
connect-all     Discover and Connect to NVMeoF subsystems
connect         Connect to NVMeoF subsystem
disconnect      Disconnect from NVMeoF subsystem
gen-hostnqn     Generate NVMeoF host NQN

以及更多。

该实用程序甚至具有插件扩展来支持供应商特定的功能。最新版本包括


intel           Intel vendor specific extensions
lnvm            LightNVM specific extensions
memblaze        Memblaze vendor specific extensions
wdc             Western Digital vendor specific extensions
huawei          Huawei vendor specific extensions
netapp          NetApp vendor specific extensions
toshiba         Toshiba NVME plugin
micron          Micron vendor specific extensions
seagate         Seagate vendor specific extensions

通过网络访问驱动器

让我们看看如何利用高速 SSD 技术并将其扩展到本地服务器之外。NVMe 不必局限于物理插入它的服务器。在此示例中,让我们在传统 TCP/IP 之上配置软 RDMA over Converged Ethernet (RoCE) 网络,并通过此方法导出/导入 NVMe 块设备。这将是您的 NVMeoF 网络。

但在继续之前,您需要了解几个概念

  • 主机:就当前环境而言,主机将是连接到远程块设备的服务器——具体来说,是 NVMe 目标。
  • 目标:目标将是跨网络和向主机服务器导出 NVMe 设备的服务器。

在本示例中,为了方便起见,我描述了使用两台虚拟机来创建网络。这样做绝对没有任何优势,我不建议任何人这样做,除非是为了跟随练习。实际上,您应该仅在连接了高速网卡的物理机上启用以下操作。话虽如此,在目标虚拟机中,让我们连接几个低容量的虚拟 NVMe 驱动器(每个 2GB)


$ sudo nvme list
Node    SN      Model    Namespace Usage     Format     FW Rev
--------------------------------------------------------------
/dev/nvme0n1  VB1234-56789  ORCL-VBOX-NVME-VER12  1  2.15 GB / 2.15 GB
 ↪512  B +  0 B  1.0
/dev/nvme0n2  VB1234-56789  ORCL-VBOX-NVME-VER12  2  2.15 GB / 2.15 GB
 ↪512   B +  0 B   1.0

(注意:上面的表格输出已编辑以适合列宽。)

同样,我一直在使用最新版本的 Ubuntu。为了准备主机和目标操作环境,请安装以下软件包


$ sudo apt install libibverbs-dev libibverbs1 rdma-core
 ↪ibverbs-utils

在某些发行版上,您可能需要指定 librxe 软件包(在 Ubuntu 上,其功能打包在 rdma-core 中)。

同样,在主机和目标上,您现在将加载所需的内核模块(有几个)


$ sudo modprobe nvme-rdma
$ sudo modprobe ib_uverbs
$ sudo modprobe rdma_ucm
$ sudo modprobe rdma_rxe
$ sudo modprobe nvmet
$ sudo modprobe nvmet-rdma

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

设置 Soft-RoCE 网络

需要在主机和目标服务器之间建立 RDMA 网络。在每台服务器上,确定要为此传输方法启用的网络接口


$ ip addr show enp0s3
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc
 ↪fq_codel state UP group default qlen 1000
    link/ether 08:00:27:15:4b:da brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.85/24 brd 192.168.1.255 scope global
     ↪dynamic enp0s3
       valid_lft 85865sec preferred_lft 85865sec
    inet6 fe80::a00:27ff:fe15:4bda/64 scope link
       valid_lft forever preferred_lft forever

让我们在首选的以太网接口之上配置 RDMA 接口,但在这样做之前,首先验证是否已存在一个


$ sudo rxe_cfg status
  Name    Link  Driver  Speed  NMTU  IPv4_addr  RDEV  RMTU
  enp0s3  yes   e1000

启用 RDMA 环境并添加以太网接口


$ sudo rxe_cfg start
$ sudo rxe_cfg add enp0s3

验证您现在是否拥有 RDMA 接口 (rxe)


$ sudo rxe_cfg status
  Name    Link  Driver  Speed  NMTU  IPv4_addr  RDEV  RMTU
  enp0s3  yes   e1000                           rxe0  (?)

您还将在 sysfs 中找到此接口的列表


$ ls /sys/class/infiniband
rxe0

在主机和目标机器上应用相同的说明后,您需要测试 RDMA 网络。

在主机上,设置服务器


$ sudo ibv_rc_pingpong -d rxe0 -g 0
  local address:  LID 0x0000, QPN 0x000011, PSN 0x5db323,
   ↪GID fe80::a00:27ff:fe48:d511
  remote address: LID 0x0000, QPN 0x000011, PSN 0x3403d4,
   ↪GID fe80::a00:27ff:fe15:4bda
8192000 bytes in 0.40 seconds = 164.26 Mbit/sec
1000 iters in 0.40 seconds = 398.97 usec/iter

在目标上,设置客户端(将 IP 替换为主机机器的 IP 地址)


$ sudo ibv_rc_pingpong -d rxe0 -g 0 192.168.1.85
  local address:  LID 0x0000, QPN 0x000011, PSN 0x3403d4,
   ↪GID fe80::a00:27ff:fe15:4bda
  remote address: LID 0x0000, QPN 0x000011, PSN 0x5db323,
   ↪GID fe80::a00:27ff:fe48:d511
8192000 bytes in 0.40 seconds = 164.46 Mbit/sec
1000 iters in 0.40 seconds = 398.50 usec/iter

如果您得到如上所示的响应,则说明您已成功在 TCP 之上配置了 RDMA 网络。

导出目标

挂载内核用户配置文件系统。这是必需的。您的所有 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 Qualified Name (NQN) 完成的。该概念与 iSCSI Qualified Name (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

还记得您为 RDMA 通信启用的以太网接口吗?嗯,导出您的子系统时将使用它的 IP 地址


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

接下来,您将设置一些其他参数


$ echo rdma|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_rdma"
[24457.458325] nvmet_rdma: enabling port 1 (192.168.1.92:4420)

导入目标

主机当前没有 NVMe 设备


$ nvme list
Node    SN     Model    Namespace Usage    Format     FW Rev
------- ------ -------- --------- -------- ---------- ------

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


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

Discovery Log Number of Records 1, Generation counter 1
=====Discovery Log Entry 0======
trtype:  rdma
adrfam:  ipv4
subtype: nvme subsystem
treq:    not specified
portid:  1
trsvcid: 4420

subnqn:  nvmet-test
traddr:  192.168.1.92

rdma_prtype: not specified
rdma_qptype: connected
rdma_cms:    rdma-cm
rdma_pkey: 0x0000

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


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

如果您返回以列出所有 NVMe 设备,您现在应该看到由该 subnqn 导出的所有设备(注意:下面的表格输出已重新格式化以适合)


$ sudo nvme list
Node    SN   Model  Namespace Usage    Format    FW Rev
------- ---- ------ --------- -------- --------- ------
/dev/nvme1n1  8e0999a558e17818  Linux   1  2.15 GB / 2.15 GB
 ↪512  B +  0 B  4.15.0-3

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


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

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


$ sudo nvme disconnect -d /dev/nvme1n1

您已经成功了:通过 NVMe over Fabrics 网络导出的远程 NVMe 块设备。您现在可以像任何其他本地连接的高性能块设备一样对其进行写入和读取。

注意:如果您看到 I/O 错误,则 Linux rxe 代码存在已知问题,您可能需要运行较新的内核。据信内核提交 2da36d44a9d54a2c6e1f8da1f7ccc26b0bc6cfec 解决了此问题,并且已合并到较后的 4.16 版本中。

总结

NVMe 驱动器改变了高速计算的格局。规范和技术都重新定义了对基于 NAND 的 SSD 介质的访问,并已更新以更好地适应现代工作负载。尽管 NVMe 通常在本地机器中运行,但它并不局限于此。使用 NVMe over Fabrics 技术,NVMe 可以扩展到本地服务器之外,并跨越整个高速网络。

资源

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

加载 Disqus 评论