笔者的实验室于近期购置了8块nvme硬盘,通过pcie转接卡转接至一台服务器,并用ZFS组了RAID。为了能让实验室的其他服务器也能快速访问主机上的存储池,笔者去闲鱼套了两块ConnectX-4 CX4121A 10Gbe 的万兆网卡用来连接两台服务器,并配置了NFS Over RDMA。
闲鱼的卖家没有附带光模块,笔者随意买了两个华为的10G模块,大概15-20元一个。
安装驱动
前往nvidia的官网下载NVIDIA Firmware Tools (MFT),根据自己的系统选安装包,笔者实验室用的都是ubuntu,就下载了mft-4.25.0-62-x86_64-deb.tgz。
下载完后运行安装包内的install.sh
即可。
安装完后通过mst start
启动MST,然后用mst status
就能看到自己的卡了,此时电脑上应该也会多出光卡对应的NIC。
# mst status
MST modules:
------------
MST PCI module is not loaded
MST PCI configuration module loaded
MST devices:
------------
/dev/mst/mt4117_pciconf0 - PCI configuration cycles access.
domain:bus:dev.fn=0000:04:00.0 addr.reg=88 data.reg=92 cr_bar.gw_offset=-1
Chip revision is: 00
如果网卡只用做服务器之间的互联,可以分别为两段的服务器配置静态IP和路由。
更新固件
前往nvidia的固件下载页下载对应的zip(注意区分自己的卡是以太网卡还是IB卡)。
找到自己的设备(/dev/mst
开头的),用flint -d <device_name> -i <binary image> burn
刷入固件。
安装MLNX_OFED
虽然笔者买的是以太网卡,但Mellanox的RDMA内核模块需要去给IB卡提供的MLNX_OFED
包里安装。MLNX_OFED
也可以在Nvidia官网下载。笔者直接下了最新的MLNX_OFED_LINUX-23.07-0.5.0.0-ubuntu22.04-x86_64.tgz,没有下LTS版本。
下载完解压后,运行里面的
./mlnxofedinstall
即可。
随后还要手动安装里面的NFS-RDMA内核模块,一般这个包位于./DEBS/mlnx-**nfs**rdma-dkms_23.04-OFED.23.04.0.5.3.1_all.deb
的位置,也可以用find . | grep nfs | grep .deb
找到。随后dpkg -i ./DEBS/mlnx-**nfs**rdma-dkms_23.04-OFED.23.04.0.5.3.1_all.deb
即可。期间需要DKMS需要build内核模块,请耐心等待。
安装NFS Server
在服务器一端安装NFS Server
apt install nfs-kernel-server
systemctl start nfs-kernel-server.service
在启动NFS之前需要mount相应的内核模块,以及把RDMA用的端口加进NFS的portlist:
/sbin/modprobe rpcrdma
echo 'rdma 20049' | tee /proc/fs/nfsd/portlist
如果想之后自动进行可以直接修改/lib/systemd/system/nfs-kernel-server.service
(主要是加ExecStartPre
和ExecStartPost
:
[Unit]
Description=NFS server and services
DefaultDependencies=no
Requires=network.target proc-fs-nfsd.mount
Requires=nfs-mountd.service
Wants=rpcbind.socket network-online.target
Wants=rpc-statd.service nfs-idmapd.service
Wants=rpc-statd-notify.service
Wants=nfsdcld.service
After=network-online.target local-fs.target
After=proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service
After=nfs-idmapd.service rpc-statd.service
After=nfsdcld.service
Before=rpc-statd-notify.service
# GSS services dependencies and ordering
Wants=auth-rpcgss-module.service
After=rpc-gssd.service gssproxy.service rpc-svcgssd.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=-/usr/sbin/exportfs -r
ExecStartPre=/sbin/modprobe rpcrdma
ExecStart=/usr/sbin/rpc.nfsd
ExecStartPost=/bin/bash -c "sleep 3 && echo 'rdma 20049' | tee /proc/fs/nfsd/portlist"
ExecStop=/usr/sbin/rpc.nfsd 0
ExecStopPost=/usr/sbin/exportfs -au
ExecStopPost=/usr/sbin/exportfs -f
ExecReload=-/usr/sbin/exportfs -r
[Install]
WantedBy=multi-user.target
随后systemctl daemon-reload
并重启nfs服务。此时在NFS的监听端口里应该能看到普通nfs用的2049和RDMA的20049了:
# cat /proc/fs/nfsd/portlist
rdma 20049
rdma 20049
tcp 2049
tcp 2049
添加暴露的挂载目录
编辑/etc/exports
,如果对于ZFS文件系统,也可以直接执行如下命令(意思是允许7.0.115.0/24
访问pool-name
这个pool):
zfs set sharenfs="[email protected]/24,no_root_squash,async" pool-name
随后通过exportfs -v
检查,可以看到相应的目录已经被暴露了:
# exportfs -v
/data/pool-name 7.0.115.0/24(async,wdelay,hide,no_subtree_check,mountpoint,sec=sys,rw,secure,no_root_squash,no_all_squash)
客户端操作
客户端在挂载前同样需要挂载rpcrdma,这个命令也可以写在systemctl的ExecStartPre=
里:
modprobe rpcrdma
随后进行挂载:
mount 7.0.115.1:/data/pool-name /data/pool-name -o rdma,port=20049,async,noatime,nodiratime -vvvv
如果一切没有问题则可以在/etc/fstab
里添加:
7.0.115.1:/data/pool-name /data/pool-name nfs rdma,port=20049,async,noatime,nodiratime 0 0
测速
用fio测试顺序写入速度:
fio --name=testfile --directory=/data/pool-name/speedtest --size=2G --numjobs=10 --rw=write --bs=1000M --ioengine=libaio --fdatasync=1 --runtime=60 --time_based --group_reporting --eta-newline=1s
可以看到写入速度能够跑满10G网卡(1078MiB/s
),同时测速时通过iftop在网卡上看不到任何流量,说明NFS的流量已经直接经过RDMA传输了。
testfile: (groupid=0, jobs=10): err= 0: pid=3968057: Thu Aug 24 08:00:00 2023
write: IOPS=1, BW=1078MiB/s (1130MB/s)(67.4GiB/64006msec); 0 zone resets
slat (msec): min=328, max=6801, avg=3973.96, stdev=1633.37
clat (nsec): min=1780, max=12590, avg=3690.00, stdev=1745.87
lat (msec): min=328, max=6801, avg=3973.96, stdev=1633.37
clat percentiles (nsec):
| 1.00th=[ 1784], 5.00th=[ 2064], 10.00th=[ 2192], 20.00th=[ 2800],
| 30.00th=[ 2928], 40.00th=[ 3088], 50.00th=[ 3280], 60.00th=[ 3408],
| 70.00th=[ 3824], 80.00th=[ 4576], 90.00th=[ 4896], 95.00th=[ 6688],
| 99.00th=[12608], 99.50th=[12608], 99.90th=[12608], 99.95th=[12608],
| 99.99th=[12608]
bw ( MiB/s): min=19984, max=20000, per=100.00%, avg=19997.62, stdev= 0.93, samples=64
iops : min= 16, max= 20, avg=19.40, stdev= 0.23, samples=64
lat (usec) : 2=2.90%, 4=71.01%, 10=24.64%, 20=1.45%
fsync/fdatasync/sync_file_range:
sync (nsec): min=20, max=9970, avg=597.50, stdev=1058.05
sync percentiles (nsec):
| 1.00th=[ 20], 5.00th=[ 50], 10.00th=[ 110], 20.00th=[ 161],
| 30.00th=[ 231], 40.00th=[ 382], 50.00th=[ 470], 60.00th=[ 532],
| 70.00th=[ 612], 80.00th=[ 708], 90.00th=[ 948], 95.00th=[ 1464],
| 99.00th=[ 9920], 99.50th=[ 9920], 99.90th=[ 9920], 99.95th=[ 9920],
| 99.99th=[ 9920]
cpu : usr=1.00%, sys=7.62%, ctx=1122377, majf=0, minf=141
IO depths : 1=233.3%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued rwts: total=0,69,0,0 short=92,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=1
Run status group 0 (all jobs):
WRITE: bw=1078MiB/s (1130MB/s), 1078MiB/s-1078MiB/s (1130MB/s-1130MB/s), io=67.4GiB (72.4GB), run=64006-64006msec