ZFS:从10Gbps升级到40Gbps网络

0 介绍

TrueNAS Core已更新至FreeBSD 13,其两款免费产品Scale和Core也已转至OpenZFS。考虑到之前一直使用SolarisZFS,可能会对OpenZFS的tuning不够熟悉,又想获得Linux的一些优势,因此使用了TrueNAS Scale。但体验不佳,后来换成了NixOS,这篇文章主要是讲述40GB网卡在TrueNAS下的使用,Infiniband和RDMA。

早些时候海淘拼车买了Mellanox SX6036,疫情闲赋在家就拿出来换了一套猫扇,NAS和Proxmox VE连接Mellanox SX6036,再连接家里的10Gbps交换机Mikrotik CRS312,至此把40Gbps网络并入整个家庭内网。

1 硬件添置

  • Mellanox SX6036交换机。闲鱼差不多2000-3000左右,但是海淘Ebay大概在600-1000左右,邮费非常贵,如果有拼车最好了,需要授权才能使用以太网ETH模式,可以自己算号得到授权的。

  • HP 544+ 40/56Gbps ETH/IB QSFP+网卡。闲鱼加转接卡一起卖大概在80-120之间,便宜一般来说带来了很多坑。

  • AOC 40Gbps QSFP网线。这个我闲鱼买的橘色的细线,价格大概在30-50元每米,比较方便理线,如果是DAC铜缆价格会更加便宜,但实在是太粗难以梳理。对了,这类线都带了模块的,你不需要再另购入模块。如果要用IB功能,线就有点贵了,自行搜索。

  • Mellanox MAM1Q00A-QSA-655874-B21 QSFP to SFP+ 转接头。闲鱼价格在100-150之间。这个转接头方便你把10Gbps的SFP+DAC线的其中一个头转换成QSFP,从而将一台10Gbps交换机和40Gbps交换机相连。

  • 如果购买了MPO多模线的用户,可以考虑购买Finisar的FTL414QB2N-E5这个模块,65元左右,此模块支持ETH并且似乎是唯一支持56G Infiniband的多模模块,价格非常便宜。

  • 如果你使用单模40GB模块,你可能无法获得任何Infiniband的收益,首先我没见过这样的模块,其次家用单模40GB模块请一定要加单模光纤衰减器,不然就是几个月烧毁,跟换灯泡差不多吧。也许单模是可以用到ROCE这种RDMA的,但即便是用多模ETH ROCE RDMA效果与Infiniband的RDMA还是差的有点多。ROCE需要交换机支持PFC ECN,而sx6036并不支持,性价比极低。


1.1 可选添置

  • 我把NAS机箱的四个8CM风扇卡槽换成了三个12CM风扇卡槽,并购买了追风者T30风扇,以解决因极高温度导致的硬盘过热问题。新的12CM风扇效果很好,因为它们具有兼具PWM和广泛转速范围的特点,而且噪音很低。此外,我还找淘宝上用PETG材质3D打印的卡槽来更换旧的卡槽。打印文件购买链接

  • Chelsio T580 40Gbps 网卡。这张卡我之前800左右买的,闲鱼现在我看有的1500,有的1000。此卡是我见过在没有RDMA情况下延迟最低的卡,并且能在MacOS下驱动。

  • 在写这篇文章的时候MacOS突然更新支持了Mellanox ConnectX-4代及以上的eth网卡的驱动,看了一下匹配非常宽泛,感觉200G的都支持,但不确定是否带有ROCE2;同时也支持了intel的几张40G以上的网卡。如果只是MacOS使用的话,推荐mcx-4131a。

    追风者T30风扇需要拨动风扇中央的开关到Advance模式才能达到3000转。


  • 早前我购买了超微SAS3的背板和SAS3的9300-8i HBA卡,这样的话可以插几块SAS的SSD,如果你的前置面板只是用来插6GB的sata机械硬盘,没有必要购买24盘位的12GB的背板以及SAS3的HBA卡。HBA卡的坑我写在另一片文章中。但处理4K小文件多队列因SATA协议限制其实效果并不理想,如果无法购买或者硬盘的RAID无法更好的提高你的Queue Depth,可以考虑使用一到两个NVME SSD组成Raid0,并通过zfs send脚本定期将Raid0的数据集备份到主池的HDD中。

    需要警惕那些仿冒机箱,避免购买到非原装或浪潮的846机箱,因为上述提到的3D打印文件可能并不适用于这些机箱。同时,也要注意辨别机箱是否为原装,是否存在仿冒电源背板,这在闲鱼非常泛滥。
    我的NAS RAID使用了两组10盘Z2,并将这两组Z2 Stripe为一组,可以说是Raid60。此外,我还放了两个ZFS热备盘以及两个SAS SSD在剩余的盘位。



2 管理SX6036

管理交换机的方法有两种:一是通过RJ45网线连接交换机的管理口后台IP进行管理,二是通过Console线(RJ45 to USB)连接进入向导模式进行管理口IP等的设置。后者具有更高的权限,能做更多的设置。

  • 使用SFP光缆和购物清单中的SFP to QSFP转换头连接10Gbps交换机和SX6036时,需要在后台的WEB UI中手动协商连接口的速率至10Gbps,否则无法通信。

  • 如果使用QSFP一分四SFP线,则需要关闭其中一个口才能使用,并在ssh管理界面中标注4口为1分4。请查阅说明书来找到关闭对应口的方法,推荐购买Console线进行管理。

  • 尽量不要使用单模40G模块,SX6036只有1、3、33、35口支持单模40G,并且需要在ssh中输入fae cable-stamping-unlock 40g_lr4来开启单模支持。如之前所提示,建议不要购买单模模块。



2.2 更换SX6036交换机的风扇

此款交换机有一个可灵活拆卸的风扇盒,风扇盒中有4个4CM的风扇;电源中有一个4CM的风扇,所有的风扇都是PWM的。
我购买了5个猫头鹰NF-A4x20 FLX 3pin风扇,因为我觉得只要接地线和12v电源两个pin就够了,这风扇满转都听不到声音,更不会有心思登录到SX6036的后台通过CLI更改风扇转速。
原装风扇接口与普通主板上4pin接口不同,风扇盒的4pin定义如下:

                         颜色                                                       定义                         
                         红                                                   +12v                         
                         蓝                                                   RPM                         
                         黄                                                   PWM                         
                         黑                                                   Black GND                         

我只把FLX版本猫头鹰的红黑两根针接上去了;如果你购买了PWM版本的猫头鹰A4风扇,这款猫扇的4pin定义如下:

                         颜色                                                       定义                         
                         蓝                                                   PWM                         
                         绿                                                   RPM                         
                         黄                                                   +12v                         
                         黑                                                   Black GND                         

更换PSU电源风扇请自行考虑安全性!!个人主观认为300W的电源换个风扇问题不大,不做参考依据!电源上4pin定义如下:

                         颜色                                                       定义                         
                         蓝                                                   PWM                         
                         黄                                                   RPM                         
                         红                                                   +12v                         
                         黑                                                   Black GND                         

猫头鹰风扇和PSU的螺丝孔大小不一样,我用自带的橡皮固定了,见效果图。
此电源好像有其他几个版本,最好用万用表自己对照一下。

若使用PWM的风扇可以在SSH或者Console界面输入如下命令来控制转速:

enable  #进入高级模式
fae mlxi2c set_fan set_fan /FAN/FAN 1 65    #1代表FAN 1; 65为转速
fae mlxi2c set_fan set_fan /PS1/FAN 1 65    #PS1代表第一个电源,此交换机可以插两个冗余

更换风扇后,无论你接2针还是4针,sx6036的指示灯都变红,不影响使用。如果有强迫症,可在淘宝买风扇转速欺骗器,十元左右一个。

效果图:
IMG_4217.jpg

待传…..

3 网卡过坑

说一下HP 544+和Chelsio T580这两张卡。

3.1 HP Mellanox 544+

如果你不太想折腾,请购买原装原厂的Mellanox卡,最好是还在维护的Mellanox 4代以上。
我买了两张544+,说明一下情况,我的NAS和计算是彻底分开的两台机器,NAS是真的只做存储,而乱七八糟玩的是一台Proxmox VE,因此买两张分别给两台机器。
HP544+这张卡是Mellanox CX354a-FCCT的套娃卡,并不能刷入原装固件。HPE官网最新的固件在TrueNas使用的话,必须把此网卡的SR-IOV功能关闭,不然可能连开机都开不了。

apt update && apt install mstflint
mstconfig -d 03:00.00 set SRIOV_EN=0

通过BIOS Legacy模式在开机引导此固件Rom的时候也可以直接进入Setup界面关闭SR-IOV,这样无需安装别的软件来设置

暂时不懂怎么在TrueNAS下修改一些内核相关的东西,并且SR-IOV在我的TrueNAS主板上不是必需品,如果你会用,则刷入下面的老固件。

我在Proxmox VE中习惯使用SR-IOV,请到HPE官网下载并刷入fw-ConnectX3Pro-rel-2_40_5072-764285-B21_Ax-CLP-8025-UEFI-14.11.42-FlexBoot-3.4.747.bin这个老版本固件。

Mellanox的驱动一般是分为两种的,一种是系统自带的驱动,比如Linux内核中自带的,还有一种是Nvdia官方提供的驱动叫OFED。OFED对各种场景有更好的调优,但因其out-of-tree的原因,你每次升级内核都需要重新编译驱动。官方的OFED已经无法在Linux 5以上的内核编译出来,毕竟这张卡已经EOL了,我看了一下要编译几乎是等于重构,所以没啥办法了,家用的话使用kernel tree上的驱动足以。


已使用kernel tree上自带的驱动并使用SR-IOV,只是发现了windows虚拟机上的VF有个小问题,下面给了解决方案了,别的没碰到啥问题。
安装mstflint,以Proxmox VE为例:

apt update && apt install mstflint

通过lspci获得Mellanox网卡的设备号并设置,例如:

lspci |grep Mellanox

03:00.0 Ethernet controller: Mellanox Technologies MT27520 Family [ConnectX-3 Pro]

mstflint -d 03:00.00 query   #获得固件信息
mstflint -d 03:00.00 -i 固件路径 b  #刷入固件
mstconfig -d 03:00.00 query    #获取设备设置信息
mstconfig -d 03:00.00 set SRIOV_EN=1 NUM_OF_VFS=8  #开启SR-IOV以及设置VF总数为8个;确保主板已开通sr-iov,Proxmox VE已开通虚拟化等设置
mstconfig -d 03:00.00 set LINK_TYPE_P1=ETH  #设置p1端口为ETH模式

创建一个/etc/modprobe.d/mlx4_core.conf填入:

options mlx4_core port_type_array=1,2 num_vfs=3,4,0 probe_vf=1,4,0
  • port_type_array=1,2 意味着第一个端口是infiniband(1);第二个端口是ETH
  • num_vfs 是VF数量,格式是a,b,c。a和b分别代表端口1和2的VF量,而C是总量。注意当两个网口都是ETH的时候才需要你计算总量,而当两个口是不同的两种模式时,只能填0。具体可以参考这个文档
  • probe_vf 格式同上;这个是为Proxmox是否载入VF的数量,因为我的PVE宿主机需要一个IB,所以我第一个口只绑定了1个口,剩下的三个IB VF用来直通,则不需在PVE载入。但是ETH是应该全都要载入的,因为ETH你需要在PVE下先载入设置MAC地址,设置完之后再直通去虚拟机。

设置完后记得update-initramfs -u后重启。

一般来说更新的是当前系统运行的内核,update-initramfs -u -k <kernel version>来更新指定的内核,或者update-initramfs -u -k $(uname -r)来更新当前使用的内核。
如果你完全不知道,也尽可能谨慎使用update-initramfs -u -k all这个指令去更新所有内核,这不是一个靠谱的操作。

创建一个shell,assign mac地址以及vf link up:

nano /opt/sr-iov.sh

内容如下

#!/bin/bash
ip link set dev enp2s0 mtu 9000  #这个你看自己需求是否要设置mtu。如果pf是1500,那么vf设置9000会有问题。
ip link set dev enp2s0 vf 0 mac ae:51:1a:2b:c0:00
ip link set dev enp2s0 vf 1 mac ae:51:1a:2b:c0:01
ip link set dev enp2s0 vf 2 mac ae:51:1a:2b:c0:02
ip link set dev enp2s0 vf 3 mac ae:51:1a:2b:c0:03
ip link set enp2s0 up
ip link set enp2s0v0 up
ip link set enp2s0v1 up
ip link set enp2s0v2 up
ip link set enp2s0v3 up

记得chmod +x /opt/sr-iov.sh

创建systemd unit开机运行

nano /etc/systemd/system/mlx-sr-iov.service

内容如下

[Unit]
Description=Script to enable MLX SR-IOV
After=network.target
Before=pveproxy.service
[Service]
Type=oneshot
ExecStart=/opt/sr-iov.sh

[Install]
WantedBy=multi-user.target

创建完执行systemctl start mlx-sr-iov.service则看到效果了;执行systemctl enable mlx-sr-iov.service则开机自动运行

注意给虚拟机增加一些延迟启动的时间。这个脚本我设置了在网络初始化完成后运行,但是在pveproxy.service(PVE的WEBUI等服务)之前执行。因为如果你的WEBUI套用了VF作为虚拟网桥,则必须要考虑这个启动顺序。
如果不是标准的服务器主板,是不具备ARI forwarding功能的,没有此功能的主板在一张网卡上无法分出超过7个以上的VF的,当然多张卡可以叠加上去。这里指的是真正的服务器主板,不包括C246那些魔改家用主板的芯片组。你在支持的主板中开启此功能,并且在系统中通过lspci -vvv | grep ARIFwd查看是否已经开启。



3.1.1 VF直通Windows Guest

如果要用Windows的VM,则尽可能使用Windows的LTSC版本。在PVE内核大于Linux 5.3的情况下(我有点记不清了),使用3代网卡的VF直通到Windows你要对Proxmox的kernel进行patch,不然Windows Guest的设备管理器里,这个VF会报错code 43,参考这里。 我把我自己patch好的放在了这里。我自己用了几个月没啥毛病才放出来了,别的奇奇怪怪的功能未经测试,我已经把kernel patch的文件放在里面了,你也可以根据自己需求定制内核。下载后通过dpkg-i *.deb安装,并且pin住这个内核。在使用这种自行修改的内核后,请非常注意apt upgrade升级的内容。

proxmox-boot-tool kernel list #查看pve下已经有的内核
proxmox-boot-tool kernel pin 5.xxx-pve #pin住内核

说实在的,Windows我都懒得用。如果对端服务器不是Windows server,那么Windows client几乎是无法跑40/56Gbps,文件管理器是串行的,SMB是单线程的,ISCSI在较新的windows 10版本中也是单线程的,我认为在windows下直接用Virtio的虚拟网卡是几乎没有什么区别的。
Linux 6.1的ksmbd内核模块似乎支持了Linux作为服务端来连接Windows客户端达到多线程以及SMB-Direct(RDMA),没时间测试。


3.1.2 Binding VF to LXC

LXC很方便通PF或者VF。通过修改/etc/pve/lxc/xxx.conf文件,加入你想要通过去的VF即可了:

lxc.net.1.type: phys
lxc.net.1.flags: up
lxc.net.1.link: enp3s0v0
lxc.net.1.hwaddr: ae:54:1c:2b:c0:00
lxc.net.1.name: eth11

lxc.net.0.type: phys
lxc.net.0.flags: up
lxc.net.0.link: enp3s0v1
lxc.net.0.hwaddr: ae:54:1c:2b:c0:01
lxc.net.0.name: eth2

####下面这部分是我的NixOS LXC使用proxmox主板的核心显卡。
lxc.cgroup2.devices.allow: c 226:0 rwm
lxc.cgroup2.devices.allow: c 226:128 rwm
lxc.cgroup2.devices.allow: c 29:0 rwm
lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir
lxc.mount.entry: /dev/fb0 dev/fb0 none bind,optional,create=file
lxc.autodev: 1
lxc.hook.autodev: sh -c "chmod -R 666 /dev/dri/card*; chmod -R 666 /dev/dri/render*"


3.1.3 把VF放入PVE的vmbr0中

因已有中文教程,自己也没啥时间写,请参照这里

3.2 Chelsio T580

Chelsio对FreeBSD的支持特别好,但在linux下的驱动些许麻烦,随手写一下在 Proxmox VE 7下面驱动此卡的方法:

  • 从官网下载最新版的tar.gz压缩包

  • 解压压缩包tar -zxvf ChelsioUwire-x.xx.x.x.tar.gz

  • 安装rpm sudo apt install rpm

  • 安装pve的linux headers

    sudo apt install pve-headers-`uname -r`
  • 确认你kernel sources的路径,应该是usr/src/linux-headers-x.xx.xx-x-pve/

  • 回到刚才解压缩好的文件夹里,修改Makefile:

    DEBIAN := 1
    PDEB := 1
    DISTRO := Debian
  • 在当前目录编译驱动 make KDIR=/usr/src/linux-headers-x.xx.xx-x-pve/

  • 完成后你可以使用此卡的高级功能 e.g.SR-IOV, etc.

  • 每次更新PVE内核你都需要重新编译驱动。



3.2.1 Chelsio T580在MacOS下的驱动

这张卡直接在官网下载驱动安装就行,如果你希望干净一点安装,在MacOS下通过命令pkgutil --expand-full [pkg] [dir]获得PKG内的KEXT。其中cxgb.kext是Chelsio T580的驱动,cxgb3.kext是T3xx系列的驱动。

这个官方驱动只支持到big sur。

这个patched驱动支持到Ventura,在MacOS下你应该要关闭SIP来加载这张过期的签名,或者如果是Hackintosh的话,使用Opencore加载这个驱动

这个卡超级超级超级热,拆卸此卡时小心灼伤,温度过高会导致掉光模块或者掉卡。一个风扇不够,你需要2-4个风扇全面覆盖它才可以;条件允许,水冷。



4 OpenZFS

对于FreeBSD而言,SolarisZFS和OpenZFS使用上差别不是那么大。但是在Linux上实现OpenZFS我暂时没明白,OpenZFS的实现固然很有用,但是在BSD里物理硬盘与VDEV是依赖于Geom去实现的,Geom提供providers给OpenZFS来做成Vdevs,则完成整一套的虚拟-物理设备之间的通信。而Linux是用mdadm来实现的,这个我也在慢慢消化中。



4.1 Ashift

Ashift则是用来设置物理硬盘的块大小 (block size)。常见的硬盘块大小有512字节、4KB、8KB等。在创建存储池时,Ashift的设置会影响存储池的性能和空间利用率。
在老的FreeNAS版本中,默认给的是Ashift=9,代表块大小为512B。这个设置方式的问题是,对于4KB大小的文件,硬盘需要切割为8份才能存储。这样会对服务器带来一定的压力,但可以尽量减少空间损失。而如果设置成更大的块大小,则会浪费空间。因此,现代的TrueNAS默认给的是Ashift=0,代表自动辨别块大小。
书籍中建议的Ashift=12,代表块大小为4KB。这样设置会尽力减小服务器压力,而浪费的空间可以通过压缩来减少损失。对于一些新的SSD,块大小可能已经达到8K,此时应将Ashift设置为13。通过如下命令可以确认自己的Ashift设置:

zpool get all PoolName |grep ashift

为什么是9和12? 2^9=512;2^12=4096。一些新的SSD已经到了8k,则ashift=13



4.2 Meta Vdevs

Meta Vdevs是近几年新出的一个功能。这个Vdev并不是一个缓存,而是一个Storage,因此,你需要确保这个Vdev有较高的安全性,比如两个optane硬盘组成一个Mirror甚至更大的冗余,如果这组Vdev坏了,在同一个Pool下的机械池数据也同样丢失。请不要想着试试看能不能用,操作尤其是在raidz的阵列上几乎不可逆。


Meta Vdevs解决了两个问题。

  • 如果你的存储池存在很多小文件,那读取或者写入都会牵扯到机械硬盘的stroke时间,io depth,queue等问题。那么,如果把pool的Metadata放在了Optane上,则至少可以减少storke的时间,也能收获到更多的IO queues,这对小文件多线程是很有帮助的。
  • 你同样可以对Meta Vdev进行设置:把特定的Block size文件存于Optane中,而没有命中规则的文件,则放入原来的机械存储池中。
    TrueNas的Pool–dataset–option中,可以看到你对这个池的Record size,比如我的是128K,然后我在下面的Metadata (speical) small block size中设置一个值,比如是64k。当一个文件≤ 64k,则自动存入Optane中。当Metadata (speical) small block size=Record size,则所有文件全会存入Optane中,显然这样做,还不如单独用Optane建立一个池。
    在看Meta Vdevs的手册时,我思考了如下两个问题:

Optane作为Meta Vdev存满了,我该怎么办?

根据手册的说法,Meta Vdev存满了,则会根据算法自动将使用频率少的文件回落到机械硬盘。

我应该选择多大的Optane来存放?

我们可以看一下你之前的一些比较具有代表性的小文件池来观察估算:

cd /mnt/poolname/test #cd到你想测试的dataset下
find . -type f -print0 | xargs -0 ls -l | awk '{ n=int(log($5)/log(2)); if (n<10) { n=10; } size[n]++ } END { for (i in size) printf("%d %d\n", 2^i, size[i]) }' | sort -n | awk 'function human(x) { x[1]/=1024; if (x[1]>=1024) { x[2]++; human(x) } } { a[1]=$1; a[2]=0; human(a); printf("%3d%s: %6d\n", a[1],substr("kMGTEPYZ",a[2]+1,1),$2) }'

看一下你的这个dataset下文件的整个block size分布,按比例预估。
另外通过如下命令也可以看到整个pool的情况,除掉L0 Total外的总和就是你的metadata目前所需要的空间。具体的一些估算以及应用方法请参考这里。当然,我们讨论的文件大小都是通过compression压缩后的大小。非Optane的SSD作为Meta Devs你需要手动开启trim on

zdb -LbbbA -U /data/zfs/zpool.cache <poolname>

最后有个小问题,metadata对于Zvol是无用的。对ZFS来说,往zvol写入多少文件都只是block size大小完全一样的存在,你可以收益到的只是Metadata对Zvol的加速。这个问题的讨论请参考这里。如果你是zvol用的频繁并且还需要更极致的zvol性能,参考章节6.ZFS Send。



4.3 Dedup Vdevs

一般来说,开启了dedup功能的dataset能做到文件去重复的作用,也就是多个一模一样的文件只占用一份文件的容量。以前用内存来做,代价是用内存换硬盘空间,现在即便是可以用Dedup Vdev来换机械硬盘空间,也不推荐。Meta Vdevs存储了dedup datasheet,同样做到了dedup功能,不如用meta dev。
开启dedup的dataset是不可逆的,请把已经开启dedup的dataset通过zfs send到新的dataset里,再删除旧的。名字的话通过zfs rename改回来。



4.4 Slog

如果说起ZFS的写缓存,往往会被误导到使用Slog,这里可以明确指出,Slog不会让你的写入速度超过当你dataset设置成async的速度的。ZFS在写入时先产生ZFS intent log(ZIL),也就是未来会写入的文件的一个操作日志,在5秒为预期的时间内,文件会先进入内存(TXG),再写入硬盘,当整个文件还没落盘,文件不具备可读性以及可执行性的情况下,我们称之为脏数据(dirty data),最后等落盘写入,整个操作完成,而这个文件通过判断可能会继续留在内存的ARC里作为未来的读缓存。我们看下来整个过程,其实ZFS并不具备传统意义上的写缓存,而是一个缓冲区为未来的读取做准备的。

另一方面这样的写入是异步操作的,在更严谨的环境中,需要同步写入(sync write)。同步写入的速度会非常慢,通过增加Slog,比如Optane这种写入快,安全性高的硬盘去帮我们提高写入速度,当然,当Optane开启了FUA bit作为Slog后,速度也不会太好看的。
总之,Slog只是保证了你文件的同步写入,家用情况,UPS足矣。



4.5 L2arc

L2arc是ZFS的读缓存。在访问ZFS时,一些常用文件会放置于内存ARC中,以便快速读取,而内存的容量是相对有限且昂贵的,因此增加一个L2arc可以让你有更大的空间去缓存常读的文件。一般来说l2arc的容量需要一部分的arc来带动,官方推荐的是你可用arc的4倍左右的容量就足够了,如果买的太大,则需要tuning你的arc.max或者l2arc.max稍作控制。l2arc不需要任何冗余,你只要买的足够快就可以了。
如果你的arc仍然在growing,请不要添加任何l2arc,这样只会有反作用,因为内存的速度永远比SSD快,但是如果你的zfs是跑在网络上,比如我的网络带宽是40g,则l2arc的速度只要达到这个速度就够了。请通过arc_summary来观察自己的内存arc做判断依据。
在设置了相应的l2arc后,也推荐通过zfs set secondarycache=metadata DatasetName把metadata都给过去,同时请关注一下这个问题



4.6 HDD Storage Pool

TrueNAS通过WebUI建立的pool非常平庸,但想了想也不知道写啥,默认的ashift=0,意味着是让系统自己判断,这里最好是自己在创建pool的时候设置好。别的一些功能应该根据不同dataset的应用去分别设置的,这个就没啥好说的了。
另外,现在机械硬盘自带的缓存越来越大了,尽管ZFS已经commit一个写入已经落盘,但在硬盘的层面上仍然会有物理的缓存落到机械硬盘磁碟的这一个过程。这个物理硬盘的缓存可以通过hdparm -W /dev/sda查看当前硬盘是否开启了,一般默认是开启的。值得探讨的是否应该关闭这个缓存:hdparm -W 0 /dev/sda。这个是否应该关闭值得探讨。



4.7 OpenZFS Tuning

ZFS 的使用优化是没有参照的,即便是跟我买完全一模一样的机器,拿回去使用场景不同都不能tuning一样的。老老实实看OpenZFS的Manual吧,没有捷径。但我可以说一下我自己的一些40Gbps网路下的Tuning思路。

  • 在内存有限的情况下使用L2arc提高读取速度。L2arc是一个高性价比的选择。在内存arc仍然growing的情况下强行使用l2arc只会让你的读取速度变慢,按现代计算机架构来看,没有啥SSD是比内存更快的。
  • L2arc的容量尽可能匹配内存arc容量的4-5倍之间,超过容量后的那部分tuning不切实际。
  • dirty data的设置需要花时间观察的,因为不同场景下的值不是一样的,也不是越大越好,需要花费大量时间观察调整,再观察调整循序渐进,没吃太饱的话还是保持默认吧。
  • 慎重考虑Meta Devs这个功能。
  • 最后提一嘴,所有的Tuning都是有代价的。


4.8 写放大优化

但凡是CoW的文件系统,都无法避免写放大的问题,在一段时间的使用后,尤其是有删除行为后,你的block会越写越碎,最后顺序写会变成随机写。这种情况在机械硬盘上尤其让人无法忍受,因为sata机械硬盘的queue非常小,虽然有很多种优化方法,比如:

  • 设置正确的record size,比如电影文件夹的话,目前openzfs 2.2以上已经支持了large record size选项。
  • 数据库类的dataset可以通过数据库软件本身的设置,设置数据库的page size来对应你dataset的record size
  • zvol也会遇到一样的问题,因此iscsi的服务端软件比如LIO,对block size设置对应的设置也有一定的帮助。

但是,如开头所说,不只是ZFS,只要这个文件系统是CoW的,即便再怎么优化都无法彻底解决的,有一些极端的办法比如把zfs_txg_timeout设置的非常高,尽量让文件写到内存里,我觉得这都不是一种比较好的办法。如果真的有一个读写非常敏感的dataset,更建议用1-2个ssd,哪怕是raid0的也行,写在上面并且每小时zfs send回HDD池,毕竟nvme的queue depth,可以硬抗这种碎片化带来的顺序写变成随机写的问题。另外,定期的阵列scrub以及trim还是很有必要的。



5 NFS Tuning

NFS对于小文件的读写是不理想的,有条件的话尽可能使用iSCSI。
NFS Version ≥ 4.1,并且在NFS Server 设置中把线程设置成24个或者更高(看你CPU),链接NAS是可以大文件跑到40Gbps的(在没有开启RDMA的情况下,这很看你的CPU配置)。如果是4k小文件请调小NAS服务端的Block Size,同样客户端的wsize rsize都理应调小。另外MTU 9000对于4k是很有用的,条件允许,开启。
MacOS依然没有更新NFS版本,并且在Finder下因为Foundation API通过版本NFS v4.0连接NAS会出现断连的情况,而在MacOS的Terminal中使用POSIX权限则没有这样的现象。
但在MacOS中,无论使用什么40Gbps卡,你都只能在GUI界面环境中获得20Gbps的连接速度,这也许是因为协议层太过老旧而用户无从选择。

如果是Samba的话,我无法给出一个标准答案,这完全取决于你CPU的单核心能力,毕竟只有上传和下载两个线程。又或者说你希望使用SMB Multi-Channels功能来解决这个问题。

Samba和SMB这两个东西实在是太畸形了,作为用户我唯一的权利就是选择不用。


6 ZFS Send

机械SATA硬盘无法与现代的SSD比肩4k类的读写,尤其是在IO Depth IOPS等方面。如果你不满足于Meta devs功能来提高4k的写入和读取,单独使用了一块SSD硬盘做日常的使用,并且设置了ZFS Send按天甚至按小时回传数据到HDD池中。

zfs send SSD/works@3 | zfs recv Home/test

ZFS Send必须先建立快照,其中3代表快照名,而后的Home/test则为机械硬盘池。同样,你可以使用TrueNas Web UI中自带的Replication Task来完成类似的操作。


7 Proxmox VE ZFS over iSCSI

在设置好TrueNAS的ZFS Pool后,另一台负责计算的Proxmox VE则不需要硬盘了。考虑无盘启动的话,可以参考很多IPXE教程,当然如果是超微主板或者Mellanox网卡可以直接使用Booting over iSCSI。超微的BIOS中直接有这个选项,Mellanox网卡的话使用它的Flexboot功能就可以了。
除了启动盘外,那各个VM Guest则需要开启Proxmox VE的ZFS over iSCSI功能。在PVE的DatacentreStorageAdd中添加。

这个ZFS over iSCSI其实和真正的还不一样,说白了只是一个远程的Zvol管理功能。

这里并没有可支持TrueNAS的iSCSI Provider。你需要使用这个插件来连接TrueNAS。

这个插件的API Password就是root的登陆密码,不是API Key

使用这个工具可以对VM Guest自动化操作snapshot。这里的快照是使用ZFS Snapshot的,可以完全利用到ZFS的功能了。链接中有好多个视频操作演示教程,这里就不赘述了。

8 IP over Infiniband

InfiniBand是一种高速网络通信技术,用于在计算机系统和数据中心中连接高性能计算、存储和网络设备。InfiniBand提供了一种高效的低延迟和高带宽的解决方案,通过使用专用硬件和协议来提高数据传输的速度和可靠性。与传统的以太网技术相比,InfiniBand提供了更高的带宽和更低的延迟。

然而,不是所有的软件都支持Infiniband,因此赋予infiniband一个IP则可以让它兼容大部分的软件协议,这种方法就是IP over Infiniband(IPoIB)。
Proxmox VE和TrueNAS都支持IPoIB。这里最好买原装的Mellanox 56GB FDR QSFP+铜缆,别的牌子可能兼容性没有这么好,闲鱼大概2米的在100元左右(线比网卡贵系列)。

首先最好找一台机器把两张HP 544+的卡的其中一个口刷成IB mode,TrueNAS系统下可能要提权apt和修改源才能完成。

lspci |grep Mellanox
03:00.0 Ethernet controller: Mellanox Technologies MT27520 Family [ConnectX-3 Pro]
mstconfig -d 03:00.00 set LINK_TYPE_P1=IB LINK_TYPE_P2=ETH #设置p1端口为IB模式

这里假设p1口是IB模式,p2口是ETH模式。

8.1 SX6036设置

  • 在SX6036的WebUI下切换profile到vpi模式,然后在端口管理处修改端口类型。我这里把1-21口设置成了ETH模式,22-36口为IB模式。

  • 在IB SM Mgmt菜单中找到base SM,选择SM Enabled来开启SM。注意,这些设置完后都要按右上角的SAVE按钮,不然重启就失效了。

    这个SM Mgmt就是Subnet manager,是用来管理IB网络的,因为网卡的固件版本的更新,用新版本的SM可能会更好一点,但是SX6036是不会再去更新SM了。我们可以通过两个地方下载到新的SM(OpenSM):下载官网的OFED包,只安装里面的OPENSM的deb包,这个是最新的,或者从apt等软件管理包里通过apt install opensm安装,这个版本在写这篇文章的时候还是2021年更新的,但也比6036上的新一点。OpenSM只需要在6036内的网络下任何机器安装一个跑就行了。实际体验下来,6036自带的SM和最新的OpenSM在我家用环境中没有啥区别。如果你使用4代及以上的卡的情况下,那么6036的SM就没用了,必须装新的了,4代以上的卡设置有很大区别,请不要拿4代以上的卡根据这个教程来设置。

8.2 Proxmox VE 设置

输入modprobe ib_ipoib加载ipoib的驱动,然后通过ip a看到加载的ib口了,一般就是叫ibp2s0或者ibp2S0d1
修改/etc/network/interfaces,按实际情况填写网卡名字,注意,这里面的网端不能跟你eth网段相同的。

auto ibp2s0
iface ibp2s0 inet static
        address  10.99.0.1
        netmask  255.255.255.0
        #pre-up echo connected > /sys/class/net/ibp2s0/mode 三代卡可以用connected模式,如果家里还有别的4代以上的卡,建议不要写这条,默认就是datagram模式
        mtu 2044

然后修改/etc/modules 开机加载ib_ipoibib_umad模块,这样开机就会自动加载IPoIB所需要的模块了。

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
ib_ipoib
ib_umad

最后输入systemctl restart networking.service生效,我们可以看到SX6036交换机的管理界面中已经有IB流量出现了。

8.3 TrueNAS 设置

在Core的BSD分支中,直接在Tunables中增加一条:

mlx4ib_load 
Value: YES
type: loaders

并在Tasks/Init/Shutdown Scripts中增加一条postinit 命令:

kldload ipoib

最后如同设置普通网卡的ip地址一样,在webui中设置与PVE同一段的ip,比如10.99.0.2/24。

如果是Scale版本的话,插上网卡在WebUI上啥都别设置,输入modprobe ib_ipoib && modprobe ib_umad后,你通过ls /sys/class/net就能知道你IB口的名字了,接着直接修改/etc/network/interfaces

auto ibs1d1
iface ibs1d1 inet static
        address  10.99.0.2
        netmask  255.255.255.0
        pre-up echo connected > /sys/class/net/ibs1d1/mode
        mtu 2044

其次,修改/etc/modules文件,增加这两个模块确保开机启动。

ib_ipoib
ib_umad

保存重启就好了,但每次系统更新都会导致其失效。



9 Remote Direct Memory Access (RDMA)

上一个章节中我们在设置好IPoIB后,我们发现虽然获得了更低的延迟,比如ping你能看到非常低的延迟,但是实际的传输速度又很慢,这主要是因为tcp/ip的overhead,协议等问题,这就非常考验你的CPU了。使用RDMA技术来解决这个问题。
Remote Direct Memory Access(远程直接内存访问,简称RDMA),是一种用于在网络中直接访问异地计算机内存的技术。传统的数据传输方式需要在发送端和接收端CPU中进行多次数据拷贝,增加了CPU的使用和数据传输的延迟。而RDMA技术可以通过网卡,让一个计算机的内存直接传输到另一个计算机的内存中,不需要CPU的干预,避免了数据拷贝和CPU资源的浪费,从而显著提高了数据传输的速度和效率。
RDMA有很多种,一般我们用InfiniBand是自带RDMA的,但是需要开启。同样在以太网络模式下(ETH)也有相应的RDMA比如iWrap, RoCE。这里我们只介绍IB的RDMA。
RDMA只有在scale中比较容易设置。

9.1 NFS over RDMA

这里分为TrueNas Scale服务端和PVE作为客户端两部分设置。因为Scale在最近的版本中换回了NFS-Kernel-Server,因此非常简单;而Core版本用的是NFS-Ganesha,我不太懂怎么弄这个玩意。

9.1.1 TrueNAS Scale 服务端

  • 接着之前的ipoib设置,对networks再进行修改一下
    auto ibs1d1
    iface ibs1d1 inet static
          address  10.99.0.2
          netmask  255.255.255.0
          #pre-up echo connected > /sys/class/net/ibs1d1/mode 三代卡可以用connected模式,如果家里还有别的4代以上的卡,建议不要写这条,默认就是datagram模式
          pre-up echo rdma 20049 > /proc/fs/nfsd/portlist
          mtu 2044
    修改/etc/modules文件,增加这三个模块确保开机启动。
    ib_ipoib
    ib_umad
    svcrdma
    重启TrueNAS,其实echo命令应该放到WEBUI的init script开机脚本里加载,我这么写主要是我太懒了。

9.1.2 Proxmox VE客户端

  • 在pve的/etc/modules中增加一个xprtrdma,保存重启。
  • 在pve中直接输入mount指令挂载nfs,这个nfs是带RDMA的,比如:
    mount -t nfs 10.99.0.2:/mnt/SSD/works /mnt/test -o vers=4.2,_netdev,rdma,port=20049,hard,intr,noatime,nodiratime,async,nolock,noacl,sec=sys,noresvport
  • 如果是在pve的webui中使用,则修改/etc/pve/storage.cfg,在nfs的池的option中增加rdma,例如:
    nfs: ib-nfs
          export /mnt/Home/Proxmox
          path /mnt/pve/ib-nfs
          server 10.99.0.2
          content snippets,vztmpl,backup,images,iso,rootdir
          options vers=4.2,proto=rdma,port=20049
          prune-backups keep-all=1
  • 在pve下输入nfsstat -m 你可以看到proto已经是RDMA了。
  • 试试NFS Over RDMA的速度吧。

9.2 ZFS over ISER

其实我几乎没有使用过scst这种iscsi,再者我也懒得在一个debian based truenas上折腾来折腾去,这部分我就想写个大方向。本质上就是scale的scst是自己魔改的,那么我们把原版的scst编译好替换掉应该就行了,但这么做的话,估计WEBUI那边的iscsi设置会有很多问题的,你要熟悉scst的cli。如果你熟悉linux的话,还是推荐用LIO更为方便简单。
最主要的是!我没有在用scale,写这个我还得抽空装一个,再者我平时工作挺忙的,在写这个博客没想到还是有很多人看的,就坚持写写吧,但我希望大家通过这里获得一些启发,主动学一些基本的zfs cli,那么在各种linux正式发行版中使用RDMA才游刃有余,不被客制化系统所束缚。

  • 在这里下载最新的scst进行编译,记得改一下truenas的启动项的位置应该是在/etc/systemd/system/scst.service.d,这个包我看还是在用rc-service。
  • 重新编译原版的scst后,你根据这里修改对应的conf文件就可以了。

没写完,有空再说。

10 性能测试

配置如下:

  • Nas Server配置:
    • CPU:7302P
    • 主板: Gigabyte MZ32-AR0
    • 内存:SK海力士HMA82GR7CJR8N-VK DDR4 Reg ECC 2666 16G x8
    • 机械硬盘:16T Seagate EXOS x 10 + 12T Seagate EXOS x10;两组RaidZ2后stripe,已经用了54%的容量了,其实有几个是酷狼pro,我记不得是多大的在哪组里了,反正没啥区别。
    • NVME1:480G Optane 905P x1 + 480G Samsung 983zet x1;组成mirror后放在了同一组机械池作为Meta Dev。
    • NVME2: 单独一组SSD Kioxia CD6 3.84T stripe, 每小时通过zfs send传回HDD池
    • 网卡:HP 544+;最新固件,关闭了SR-IOV
    • SAS卡:LSI 9300-8i
    • 背板:超微BPN-SAS3-846EL1
    • 系统:NixOS 22.05
  • Proxmox VE Client 配置:
    • CPU:E-2186G
    • 主板:超微X11-SCA-F
    • 内存:Samsung DDR4 UDIMM ECC 2666 16G x8
    • 机械硬盘:无
    • NVME:无
    • 网卡:HP 544+;老固件,开了SR-IOV
    • 内核:Linux 6.0.15 自己patch的

IPoIB ping

通过IPoIB连接PVE和TrueNAS(最近把TrueNAS删了换成了NixOS),再通过ZFS over iser跑虚拟机。下面测试中10.99.0.0是IPoIB,10.10.10.0是ETH
通过ping测了一下latency

PING 10.99.0.2 (10.99.0.2) 56(84) bytes of data.
64 bytes from 10.99.0.2: icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from 10.99.0.2: icmp_seq=2 ttl=64 time=0.069 ms
64 bytes from 10.99.0.2: icmp_seq=3 ttl=64 time=0.079 ms
64 bytes from 10.99.0.2: icmp_seq=4 ttl=64 time=0.051 ms 
PING 10.10.10.11 (10.10.10.11) 56(84) bytes of data.
64 bytes from 10.10.10.11: icmp_seq=1 ttl=64 time=0.296 ms
64 bytes from 10.10.10.11: icmp_seq=2 ttl=64 time=0.224 ms
64 bytes from 10.10.10.11: icmp_seq=3 ttl=64 time=0.237 ms
64 bytes from 10.10.10.11: icmp_seq=4 ttl=64 time=0.254 ms

IBping

在PVE和NAS之间通过ibping 10000个packets

--- nix-nas.(none) (Lid 4) ibping statistics ---
10000 packets transmitted, 10000 received, 0% packet loss, time 77 ms
rtt min/avg/max = 0.003/0.007/0.024 ms

ISER

在PVE上连接iser,是SSD那个池
以下是4k随机写入 24线程psync:

fio -filename=/dev/sdb -direct=1 -ioengine=psync -bs=4k -size=10G -numjobs=24 -iodepth=32 -runtime=60 -thread -rw=randwrite -group_reporting -name="randwrite"
randwrite: (g=0): rw=randwrite, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=32
...
fio-3.25
Starting 24 threads
Jobs: 24 (f=24): [w(24)][100.0%][w=510MiB/s][w=130k IOPS][eta 00m:00s]
randwrite: (groupid=0, jobs=24): err= 0: pid=176142: Sun May 21 17:26:35 2023
  write: IOPS=132k, BW=518MiB/s (543MB/s)(30.3GiB/60001msec); 0 zone resets
    clat (usec): min=35, max=19045, avg=180.20, stdev=61.22
     lat (usec): min=35, max=19046, avg=180.35, stdev=61.22
    clat percentiles (usec):
     |  1.00th=[  130],  5.00th=[  147], 10.00th=[  155], 20.00th=[  163],
     | 30.00th=[  167], 40.00th=[  172], 50.00th=[  178], 60.00th=[  182],
     | 70.00th=[  188], 80.00th=[  194], 90.00th=[  208], 95.00th=[  221],
     | 99.00th=[  253], 99.50th=[  297], 99.90th=[  502], 99.95th=[  758],
     | 99.99th=[ 3130]
   bw (  KiB/s): min=482416, max=577304, per=100.00%, avg=530297.19, stdev=936.60, samples=2856
   iops        : min=120604, max=144326, avg=132574.20, stdev=234.14, samples=2856
  lat (usec)   : 50=0.01%, 100=0.16%, 250=98.74%, 500=0.99%, 750=0.05%
  lat (usec)   : 1000=0.01%
  lat (msec)   : 2=0.02%, 4=0.01%, 10=0.01%, 20=0.01%
  cpu          : usr=0.95%, sys=2.09%, ctx=7949914, majf=0, minf=0
  IO depths    : 1=100.0%, 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,7949243,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=32

Run status group 0 (all jobs):
  WRITE: bw=518MiB/s (543MB/s), 518MiB/s-518MiB/s (543MB/s-543MB/s), io=30.3GiB (32.6GB), run=60001-60001msec

Disk stats (read/write):
  sdb: ios=110/7935683, merge=0/2, ticks=8/1393327, in_queue=1393335, util=99.89%


以下是1M顺序写入 24线程psync:

fio -filename=/dev/sdb -direct=1 -ioengine=psync -bs=1M -size=10G -numjobs=24 -iodepth=32 -runtime=60 -thread -rw=write -group_reporting -name="seqwrite"
seqwrite: (g=0): rw=write, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=psync, iodepth=32
...
fio-3.25
Starting 24 threads
Jobs: 1 (f=1): [_(14),W(1),_(9)][98.1%][w=1576MiB/s][w=1575 IOPS][eta 00m:01s]          
seqwrite: (groupid=0, jobs=24): err= 0: pid=176521: Sun May 21 17:28:31 2023
  write: IOPS=4808, BW=4808MiB/s (5042MB/s)(240GiB/51114msec); 0 zone resets
    clat (usec): min=450, max=61358, avg=4775.89, stdev=1543.22
     lat (usec): min=475, max=61501, avg=4840.36, stdev=1543.55
    clat percentiles (usec):
     |  1.00th=[ 1467],  5.00th=[ 3097], 10.00th=[ 3523], 20.00th=[ 3916],
     | 30.00th=[ 4178], 40.00th=[ 4359], 50.00th=[ 4555], 60.00th=[ 4817],
     | 70.00th=[ 5014], 80.00th=[ 5407], 90.00th=[ 6063], 95.00th=[ 6980],
     | 99.00th=[10552], 99.50th=[12911], 99.90th=[17957], 99.95th=[20579],
     | 99.99th=[26608]
   bw (  MiB/s): min= 4000, max= 6883, per=100.00%, avg=4955.55, stdev=33.42, samples=2359
   iops        : min= 4000, max= 6882, avg=4955.39, stdev=33.41, samples=2359
  lat (usec)   : 500=0.04%, 750=0.52%, 1000=0.12%
  lat (msec)   : 2=0.49%, 4=21.63%, 10=75.94%, 20=1.21%, 50=0.06%
  lat (msec)   : 100=0.01%
  cpu          : usr=1.43%, sys=0.50%, ctx=246687, majf=0, minf=0
  IO depths    : 1=100.0%, 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,245760,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=32

Run status group 0 (all jobs):
  WRITE: bw=4808MiB/s (5042MB/s), 4808MiB/s-4808MiB/s (5042MB/s-5042MB/s), io=240GiB (258GB), run=51114-51114msec

Disk stats (read/write):
  sdb: ios=270/491442, merge=0/0, ticks=63/2193831, in_queue=2193894, util=99.79%


NFS over RDMA

这里连接的是HDD的池。
1M顺序写入 24线程 psync,机械池。

fio -filename=write -direct=1 -ioengine=psync -bs=1M -size=10G -numjobs=24 -iodepth=32 -runtime=60 -thread -rw=write -group_reporting -name="write"
write: (g=0): rw=write, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=psync, iodepth=32
...
fio-3.25
Starting 24 threads
Jobs: 24 (f=24): [W(24)][97.9%][w=5141MiB/s][w=5141 IOPS][eta 00m:01s]
write: (groupid=0, jobs=24): err= 0: pid=178298: Sun May 21 17:38:07 2023
  write: IOPS=5142, BW=5142MiB/s (5392MB/s)(240GiB/47790msec); 0 zone resets
    clat (usec): min=569, max=27777, avg=4633.72, stdev=757.33
     lat (usec): min=592, max=27806, avg=4664.18, stdev=761.07
    clat percentiles (usec):
     |  1.00th=[ 3916],  5.00th=[ 4293], 10.00th=[ 4359], 20.00th=[ 4424],
     | 30.00th=[ 4490], 40.00th=[ 4490], 50.00th=[ 4555], 60.00th=[ 4555],
     | 70.00th=[ 4621], 80.00th=[ 4686], 90.00th=[ 4752], 95.00th=[ 4883],
     | 99.00th=[ 7635], 99.50th=[ 8455], 99.90th=[15139], 99.95th=[17433],
     | 99.99th=[19792]
   bw (  MiB/s): min= 3902, max= 5414, per=100.00%, avg=5145.63, stdev=12.45, samples=2280
   iops        : min= 3902, max= 5414, avg=5145.60, stdev=12.44, samples=2280
  lat (usec)   : 750=0.01%, 1000=0.01%
  lat (msec)   : 2=0.04%, 4=1.15%, 10=98.49%, 20=0.29%, 50=0.01%
  cpu          : usr=0.73%, sys=1.00%, ctx=322779, majf=0, minf=0
  IO depths    : 1=100.0%, 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,245760,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=32

Run status group 0 (all jobs):
  WRITE: bw=5142MiB/s (5392MB/s), 5142MiB/s-5142MiB/s (5392MB/s-5392MB/s), io=240GiB (258GB), run=47790-47790msec


4k随机写 24线程 psync,机械池。

fio -filename=randwrite -direct=1 -ioengine=psync -bs=4k -size=10G -numjobs=24 -iodepth=32 -runtime=60 -thread -rw=randwrite -group_reporting -name="randwrite"
randwrite: (g=0): rw=randwrite, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=32
...
fio-3.25
Starting 24 threads
Jobs: 24 (f=24): [w(24)][100.0%][w=189MiB/s][w=48.5k IOPS][eta 00m:00s]
randwrite: (groupid=0, jobs=24): err= 0: pid=177907: Sun May 21 17:36:12 2023
  write: IOPS=81.3k, BW=318MiB/s (333MB/s)(18.6GiB/60003msec); 0 zone resets
    clat (usec): min=45, max=145511, avg=293.97, stdev=887.94
     lat (usec): min=45, max=145511, avg=294.15, stdev=887.94
    clat percentiles (usec):
     |  1.00th=[   78],  5.00th=[   85], 10.00th=[   88], 20.00th=[   92],
     | 30.00th=[   95], 40.00th=[   98], 50.00th=[  102], 60.00th=[  109],
     | 70.00th=[  143], 80.00th=[  255], 90.00th=[  529], 95.00th=[  963],
     | 99.00th=[ 3228], 99.50th=[ 4359], 99.90th=[10552], 99.95th=[14746],
     | 99.99th=[28705]
   bw (  KiB/s): min=27632, max=934848, per=100.00%, avg=326662.59, stdev=8797.03, samples=2856
   iops        : min= 6908, max=233712, avg=81665.65, stdev=2199.26, samples=2856
  lat (usec)   : 50=0.01%, 100=46.46%, 250=33.26%, 500=9.61%, 750=3.95%
  lat (usec)   : 1000=1.89%
  lat (msec)   : 2=2.27%, 4=1.94%, 10=0.50%, 20=0.09%, 50=0.02%
  lat (msec)   : 100=0.01%, 250=0.01%
  cpu          : usr=0.65%, sys=1.38%, ctx=5699062, majf=0, minf=0
  IO depths    : 1=100.0%, 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,4880906,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=32

Run status group 0 (all jobs):
  WRITE: bw=318MiB/s (333MB/s), 318MiB/s-318MiB/s (333MB/s-333MB/s), io=18.6GiB (19.0GB), run=60003-60003msec


ZFS over ISER

虚拟机直接通了PVE上的iscsi,那个iscsi的zvol是SSD的池。方法大概是修改/etc/pve/qemu-server/xxx.conf:

scsi0: /dev/disk/by-id/scsi-3600140512333f9ef3744ed7bc7c2527f,size=100G,ssd=1

以下是在KVM虚拟机Ubuntu下跑的,4k随机 24线程 psync:

fio -filename=randwrite -direct=1 -ioengine=psync -bs=4k -size=10G -numjobs=24 -iodepth=32 -runtime=60 -thread -rw=randwrite -group_reporting -name="randwrite"
randwrite: (g=0): rw=randwrite, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=32
...
fio-3.28
Starting 24 threads
Jobs: 24 (f=24): [w(24)][100.0%][w=41.9MiB/s][w=10.7k IOPS][eta 00m:00s]
randwrite: (groupid=0, jobs=24): err= 0: pid=5532: Sun May 21 17:51:08 2023
  write: IOPS=18.7k, BW=73.0MiB/s (76.5MB/s)(4378MiB/60003msec); 0 zone resets
    clat (usec): min=64, max=104970, avg=1283.01, stdev=3124.97
     lat (usec): min=64, max=104970, avg=1283.23, stdev=3124.99
    clat percentiles (usec):
     |  1.00th=[   83],  5.00th=[   87], 10.00th=[   92], 20.00th=[   99],
     | 30.00th=[  119], 40.00th=[  167], 50.00th=[  208], 60.00th=[  247],
     | 70.00th=[  302], 80.00th=[  408], 90.00th=[ 5669], 95.00th=[ 8586],
     | 99.00th=[14746], 99.50th=[15795], 99.90th=[17433], 99.95th=[18482],
     | 99.99th=[33424]
   bw (  KiB/s): min=17064, max=391024, per=100.00%, avg=75022.99, stdev=4135.19, samples=2856
   iops        : min= 4266, max=97756, avg=18755.73, stdev=1033.80, samples=2856
  lat (usec)   : 100=21.50%, 250=39.43%, 500=23.41%, 750=1.20%, 1000=0.37%
  lat (msec)   : 2=1.11%, 4=1.59%, 10=7.95%, 20=3.41%, 50=0.03%
  lat (msec)   : 100=0.01%, 250=0.01%
  cpu          : usr=0.33%, sys=1.79%, ctx=1762463, majf=0, minf=0
  IO depths    : 1=100.0%, 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,1120875,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=32

Run status group 0 (all jobs):
  WRITE: bw=73.0MiB/s (76.5MB/s), 73.0MiB/s-73.0MiB/s (76.5MB/s-76.5MB/s), io=4378MiB (4591MB), run=60003-60003msec

Disk stats (read/write):
  sda: ios=0/1123915, merge=0/71430, ticks=0/207957, in_queue=207963, util=99.88%

虚拟机Ubuntu下,1M顺序写 24线程 psync:

fio -filename=write -direct=1 -ioengine=psync -bs=1M -size=10G -numjobs=24 -iodepth=32 -runtime=60 -thread -rw=write -group_reporting -name="write"
write: (g=0): rw=write, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=psync, iodepth=32
...
fio-3.28
Starting 24 threads
Jobs: 24 (f=24): [W(24)][100.0%][w=3311MiB/s][w=3311 IOPS][eta 00m:00s]
write: (groupid=0, jobs=24): err= 0: pid=5469: Sun May 21 17:49:44 2023
  write: IOPS=3063, BW=3063MiB/s (3212MB/s)(179GiB/60008msec); 0 zone resets
    clat (usec): min=425, max=119934, avg=7775.27, stdev=4139.62
     lat (usec): min=451, max=119976, avg=7832.54, stdev=4142.63
    clat percentiles (usec):
     |  1.00th=[   611],  5.00th=[   848], 10.00th=[  4883], 20.00th=[  6194],
     | 30.00th=[  6718], 40.00th=[  7242], 50.00th=[  7701], 60.00th=[  8094],
     | 70.00th=[  8586], 80.00th=[  9241], 90.00th=[ 10290], 95.00th=[ 11338],
     | 99.00th=[ 20055], 99.50th=[ 30540], 99.90th=[ 55837], 99.95th=[ 69731],
     | 99.99th=[116917]
   bw (  MiB/s): min= 1092, max= 3761, per=100.00%, avg=3068.96, stdev=19.31, samples=2856
   iops        : min= 1092, max= 3761, avg=3067.40, stdev=19.31, samples=2856
  lat (usec)   : 500=0.06%, 750=4.13%, 1000=1.07%
  lat (msec)   : 2=0.56%, 4=1.51%, 10=80.77%, 20=10.90%, 50=0.86%
  lat (msec)   : 100=0.13%, 250=0.01%
  cpu          : usr=1.03%, sys=0.39%, ctx=367956, majf=0, minf=1
  IO depths    : 1=100.0%, 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,183806,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=32

Run status group 0 (all jobs):
  WRITE: bw=3063MiB/s (3212MB/s), 3063MiB/s-3063MiB/s (3212MB/s-3212MB/s), io=179GiB (193GB), run=60008-60008msec

Disk stats (read/write):
  sda: ios=0/183581, merge=0/108, ticks=0/623119, in_queue=623127, util=99.94%

Perftest

在NAS和PVE两台物理机之间跑perftest

以下是ib_write_bw

---------------------------------------------------------------------------------------
                    RDMA_Write BW Test
 Dual-port       : OFF          Device         : mlx4_0
 Number of qps   : 1            Transport type : IB
 Connection type : RC           Using SRQ      : OFF
 PCIe relax order: ON
 ibv_wr* API     : OFF
 TX depth        : 128
 CQ Moderation   : 1
 Mtu             : 2048[B]
 Link type       : IB
 Max inline data : 0[B]
 rdma_cm QPs     : OFF
 Data ex. method : Ethernet
---------------------------------------------------------------------------------------
 local address: LID 0x04 QPN 0x0255 PSN 0x5aff2c RKey 0x90010100 VAddr 0x007ff8e4722000
 remote address: LID 0x02 QPN 0x0264 PSN 0x89e18 RKey 0x8030c18 VAddr 0x007fcda477b000
---------------------------------------------------------------------------------------
 #bytes     #iterations    BW peak[MB/sec]    BW average[MB/sec]   MsgRate[Mpps]
Conflicting CPU frequency values detected: 3000.000000 != 3300.384000. CPU Frequency is not max.
 65536      469709           0.00               5871.31            0.093941
Conflicting CPU frequency values detected: 3000.000000 != 3299.814000. CPU Frequency is not max.
 65536      469523           0.00               5869.03            0.093905
Conflicting CPU frequency values detected: 3000.000000 != 3259.731000. CPU Frequency is not max.
 65536      469685           0.00               5871.09            0.093937
Conflicting CPU frequency values detected: 3279.238000 != 3000.000000. CPU Frequency is not max.
 65536      469546           0.00               5869.18            0.093907
Conflicting CPU frequency values detected: 3000.000000 != 3299.655000. CPU Frequency is not max.
 65536      469684           0.00               5871.05            0.093937
--------------------------------------------------------------------------------------

以下是ib_write_lat

--------------------------------------------------------------------------------------
                    RDMA_Write Latency Test
 Dual-port       : OFF          Device         : mlx4_0
 Number of qps   : 1            Transport type : IB
 Connection type : RC           Using SRQ      : OFF
 PCIe relax order: OFF
 ibv_wr* API     : OFF
 TX depth        : 1
 Mtu             : 2048[B]
 Link type       : IB
 Max inline data : 220[B]
 rdma_cm QPs     : OFF
 Data ex. method : Ethernet
---------------------------------------------------------------------------------------
 local address: LID 0x04 QPN 0x0256 PSN 0x9363e6 RKey 0x98010100 VAddr 0x00000000d23000
 remote address: LID 0x02 QPN 0x0265 PSN 0xf60716 RKey 0x10030c18 VAddr 0x0055836d79c000
---------------------------------------------------------------------------------------
 #bytes #iterations    t_min[usec]    t_max[usec]  t_typical[usec]    t_avg[usec]    t_stdev[usec]   99% percentile[usec]   99.9% percentile[usec] 
Conflicting CPU frequency values detected: 3000.000000 != 3299.067000. CPU Frequency is not max.
Conflicting CPU frequency values detected: 3000.000000 != 3297.173000. CPU Frequency is not max.
 2       1000          1.01           2.56         1.07                1.10             0.03            1.40 
--------------------------------------------------------------------------------------

以下是ib_read_bw

---------------------------------------------------------------------------------------
                    RDMA_Read BW Test
 Dual-port       : OFF          Device         : mlx4_0
 Number of qps   : 1            Transport type : IB
 Connection type : RC           Using SRQ      : OFF
 PCIe relax order: ON
 ibv_wr* API     : OFF
 TX depth        : 128
 CQ Moderation   : 1
 Mtu             : 2048[B]
 Link type       : IB
 Outstand reads  : 16
 rdma_cm QPs     : OFF
 Data ex. method : Ethernet
---------------------------------------------------------------------------------------
 local address: LID 0x04 QPN 0x0258 PSN 0x48418e OUT 0x10 RKey 0xa8010100 VAddr 0x007f440f3bb000
 remote address: LID 0x02 QPN 0x0267 PSN 0xc3159e OUT 0x10 RKey 0x20030c18 VAddr 0x007f6769c2f000
---------------------------------------------------------------------------------------
 #bytes     #iterations    BW peak[MB/sec]    BW average[MB/sec]   MsgRate[Mpps]
Conflicting CPU frequency values detected: 2930.376000 != 3000.000000. CPU Frequency is not max.
 65536      436871           0.00               5460.75            0.087372
Conflicting CPU frequency values detected: 3000.000000 != 1876.346000. CPU Frequency is not max.
 65536      435374           0.00               5442.16            0.087075
Conflicting CPU frequency values detected: 3000.000000 != 3299.691000. CPU Frequency is not max.
 65536      435425           0.00               5442.79            0.087085

以下是ib_read_lat

---------------------------------------------------------------------------------------
                    RDMA_Read Latency Test
 Dual-port       : OFF          Device         : mlx4_0
 Number of qps   : 1            Transport type : IB
 Connection type : RC           Using SRQ      : OFF
 PCIe relax order: ON
 ibv_wr* API     : OFF
 TX depth        : 1
 Mtu             : 2048[B]
 Link type       : IB
 Outstand reads  : 16
 rdma_cm QPs     : OFF
 Data ex. method : Ethernet
---------------------------------------------------------------------------------------
 local address: LID 0x04 QPN 0x0257 PSN 0x147e9c OUT 0x10 RKey 0xa0010100 VAddr 0x000000021ab000
 remote address: LID 0x02 QPN 0x0266 PSN 0x62a237 OUT 0x10 RKey 0x18030c18 VAddr 0x0055e271b30000
---------------------------------------------------------------------------------------
 #bytes #iterations    t_min[usec]    t_max[usec]  t_typical[usec]    t_avg[usec]    t_stdev[usec]   99% percentile[usec]   99.9% percentile[usec] 
Conflicting CPU frequency values detected: 3000.000000 != 3242.373000. CPU Frequency is not max.
Conflicting CPU frequency values detected: 3000.000000 != 3242.780000. CPU Frequency is not max.
 2       1000          2.02           28.12        2.08                2.48             0.77            3.73                    28.12  
---------------------------------------------------------------------------------------

10 关于MTU

一般来说,除非你一定要用ETH的RDMA(RoCE),我们需要设置MTU 9000, AKA Jumbo Frames,去提高小文件的读写速度,但这个MTU有一个问题是如果你家里有一些智能的联网设备无法设置MTU,这些设备可能会联网异常的,因此我们要处理一下。有很多种处理方法比如划分VLAN等,但考虑每个人家中网络拓扑都不一样,就说一下简单的一个基本框架。

SX6036内的ETH全部走MTU 9000,然后SX6036连接到你家中万兆或者千兆的交换机这一段也设置成9000,而万兆/千兆的交换机接到家中的AP那些低速网络层全部使用MTU 1500。
网络inbound的话,也许需要修正mss,具体看你git clone之类的命令会不会遇到TLS握手问题。Mikrotik ROS则加一条mangle:

/ip firewall mangle add action=change-mss chain=forward new-mss=clamp-to-pmtu passthrough=yes protocol=tcp tcp-flags=syn

如果更为复杂的网络情况,要用到VLAN则实在没法写一个说明了,请自行脑补。
尽可能使用Infiniband网络,因为Infiniband内的网络走多少帧,跟你家中的以太网络毫无关系,解决很多烦恼。


11 补充

  • 非常喜欢用网卡ipxe+Ventoy这套东西跑系统,最近发现Mikrotik ROS系统在DHCP Server选项中增加了一个Option Matcher的功能。配合Option 93可以根据主板的架构分配不同的引导文件e.g.ArmUEFI,LegacyBIOS,x86UEFI.
  • 关于MacOS使用RDMA,答案是可以,但只能用ATTO的雷电网卡,因为苹果给的那些4代以上网卡的driverkit驱动目前是残疾的。但ATTO的kext驱动可以做到,并且效果还算不错,无法分享,有太多签名,适配不同系统的问题了,有条件自己port一下吧。
  • 关于4代-5代卡,最近老黄发了这两代卡的一些EOL Notice,闲鱼价格断崖式下降,还是老黄刀法准啊,我捡了一张456A试了一下设置以及实现方式都完全不同,有空补充。
  • 关于Ksmbd的smb多线程以及RDMA,因为我自己从来不使用windows,虽然问的人多,但我真的懒得搞,这玩意现在要在编译内核的时候设置那些SMB-Direct之类的功能。我觉得好像不用Windows不就解决了所有问题了吗?
下一篇