记录一次不严谨的ZVOL虚拟机顺序写入性能的测试

一直以来对于建构在ZVOL上面的虚拟机磁盘性能都不太满意。今天机缘巧合,测试一下,看看如何提高顺序的写入性能。

记录

测试平台

  • Host OS: Proxmox VE 7.4
  • CPU: i5 7600K
  • RAM: 64GB DDR4 2400 No-ECC
  • Motherboard: Gigabyte Z270p-D3
  • Host File System: ZFS
  • 一个非常不入流的SATA转接卡:基于ASMedia asm1061的PCIE 3.0 x1转4口SATA
  • M.2 NVME: ADATA 850 2T
  • HDD: 2 x Seagate EXOS 14TB + 1 WD EDGZ 14TB

测试方法非常的粗暴

  • PVE 上面一个单独的NVMe,做单盘ZFS
  • 在这个单盘ZFS上面创建ZVOL,在其上创建VM
    • VM系统选择Xubuntu
    • 这个 ZFS pool 上面不跑 PVE 的root。这个pool单纯只跑VM的images
  • 另外有一个TrueNAS Scale的VM。
    • 直通ASMedia asm1061给Truenas
    • ZFS Mirror: Seagate EXOS 14TB + WD EDGZ 14TB
      • 三路Mirror,理论上读取速度应为单盘3倍,写入速度还是1倍。
  • TrueNAS管理的ZFS mirror,通过SAMBA share,分享给Xubuntu。
  • 在Xubuntu上面通过 Copy一个40GB的文件来测试大文件顺序写入的性能。

一些测试中没有改变过的细节参数

  • TrueNAS VM的RAM:16GB
  • TrueNAS ZFS Mirror dataset的recordsize: 128k
  • TrueNAS ZFS Mirror dataset已用空间:~1TB
  • TrueNAS和Xubuntu的网络连接:virtual bridge,理论上跑10Gbe应该是没有问题的,保证网速不是瓶颈。
💡
即使是virtual bridge,性能上限达到并超过10Gbe应该不成问题,但是MTU设置依旧是1500,以保证兼容性。后续测试结果来看,受限于HDD的读取性能,此设定应该不是瓶颈。

以下就是测试的流水账了。

  • Baseline: volblocksize: 16k, 在QEMU的config里面没有添加 args: -global scsi-hd.physical_block_size=16384, VM文件系统: EXT4, CPU cores: 2。
    • 使用 sudo tune2fs -l /dev/sda3 检查,确认 RAID stride 和 stripe 都是1,也就是说VM上面的文件系统不认为Virtual Disk上有RAID。
    • 用默认的文件管理器Thunar,速度在170MB/s左右。
  • 在QEMU的config里面添加args: -global scsi-hd.physical_block_size=16384,重新安装系统
    • sudo tune2fs -l /dev/sda3 确认RAID stride 和 stripe 都是4.
    • Thunar测试速度还是在170MB/s左右。
  • 在PVE->Hardware里面,设定Harddrive,选上SSD Emulate 和 Discard
    • Thunar测试发现速度没变。
  • 在PVE主机上测试(mount samba share, then use rsync -ahP to the ‘fastpool’)
    • 这时’fastpool’是一个dataset,而不是VM里面用的ZVOL
    • 速度在400MB/s到600MB/s之间。应该是一个合理的3-way mirror HDD的读取速度。稳定的性能大概有440MB/s吧。
  • CPU类型改为Host
    • 依旧是170MB/s左右
  • Harddrive Async IO改为native , threads
    • 依旧是170MB/s左右。使用 threads 的时候似乎性能更差了一些。
  • Harddrive Async IO改回default (uring),CPU cores 从2添加到4。
    • 速度大体能提升到220MB/s
    • 在cores=2的时候,Samba copy的时候CPU占用率在65%左右。没想到这时候给更多的核居然可以提高一点性能。但是距离440MB/s还有很远。
  • 内存从2GB提升到8GB
    • 没有变化,甚至有些不稳定,在170到220之间飘忽不定。
  • 把ZVOL的volblocksize改为64K,重新创建VM,添加args: -global scsi-hd.physical_block_size=65536,然后重新安装系统。
    • 没有变化
    • 这个args: -global scsi-hd.physical_block_size=65536 似乎对于顺序写入的影响不大(可以说基本没有任何影响)。
  • 把ZVOL的volblocksize改为128K,重新创建VM以及安装系统。
    • 系统的安装速度似乎变慢了一些。也许是小文件的写入性能已经劣化了。
    • 1 Core CPU: 大文件顺序写入还是在200MB/s左右。
    • 4 Core CPU: 250MB/s左右。
    • Async IO = native: 最高270MB/s左右。稳定的速度还是在250MB/s左右。
    • Cache改为write back:性能劣化,基本稳定在200MB/s左右。
    • VM的ZVOL的logbias从latency,改为throughput:没有变化。
    • 添加 scsi-hd.physical_block_size=131072 :没有变化。
    • 尝试文件系统改为XFS(根据):没有变化。
    • 尝试使用新的专用vmbr虚拟网口:没有变化。
  • 不用文件管理器Copy,而是在VM上面 mount Samba share,然后使用rsync -ahP 来copy这个40GB大文件:
    • 速度可以相对稳定在350MB/s。
    • 最高可以达到450MB/s,甚至瞬时可以达到500MB/s以上。
    • 证实了Thunar这个文件管理器在处理Samba的时候,性能有损耗!
  • 改回volblocksize=16k的虚拟机(依旧是4 core CPU,8GB)
    • rsync速度下降为稳定在300MB/s以上,时不时在350MB/s左右。相比volblocksize=128k的情况,性能还是有所下降的。
  • 在VM里面直接使用fio 写入 1M blocksize的8GB文件
    • 速度可以高达1.6GB/s
    • 但是不是很确定fio是不是都写入的0.
💡
Samba的挂载采用的是version 3.0。不确定是不是相比 version 1.0有性能上的提升。

结论

  • Thunar的Samba性能有坑,不应当作为Samba读取性能的测试方式,甚至实际使用中还会有性能问题。
  • 128k vs 16k 的volblocksize,对于其上运行的VM来讲,对于大文件的顺序写入性能还是有影响的。对于小文件写入应该也有影响,128K的应该对小文件写入有很大的负面影响,可能会有很大的写入放大。
  • 从3-way HDD ZFS mirror rsync出来一个40GB的大文件,如果目的地是一个足够快的zfs dataset,440MB/s的速度大概就是稳定速度了。极速可能可以到600MB/s。此时,一个不入流的SATA -> PCIE卡还可以应付。由此推断,PCIE 3.0 x1的4口SATA,在全接HDD的情况下,应该大概还不会成为性能瓶颈(PCIE 3.0 x1 理论速度上限 8Gbps 即 1GB/s)。同理一个PCIE 2.0 x1 转 2口SATA的卡,大概也还能继续发挥余热。
  • 但是一旦使用SSD,那么不上正经的PCIE 3.0 的HBA卡就说要不过去了。
  • VM里面的速度目前最多也只能接近400MB/s,这是在使用128K的volblocksize的情况下,而且是使用了XFS(大文件方面XFS应当比EXT4性能更强,但是对于这次的单纯顺序写入,我认为应该是没有差异的。)
  • args: -global scsi-hd.physical_block_size=<your_volblocksize_in_bytes> 确实可以在VM系统安装格盘的时候,指导分区程序。做出来的文件系统,哪怕blocksize定死为4K的系统,也会认为下面的physical blocksize 是指定的这个大小。也许在小文件和随机写入方面,能够提高性能,减少写入放大的问题。不过在大文件顺序写入的时候,这个设定用处不大。

最终还是在VM里面把Samba中大文件的连续读取,写入本地磁盘的性能,从170MB/s提高到了300MB/s,甚至接近400MB/s。这里面主要因素大体应该是:volblocksize 16k vs 128k,rsync vs thunar,CPU 1 core vs 4 core。而其他一些设定比如 async io (default uring vs native),cache (no cache vs write back),ssd emulate,RAM size,XFS vs EXT4,都影响不大。

这次测试的这个 VM 用的 ZFS pool 是开启了 thin provision的。这个也许对 ZVOL 上面模拟出来的 block 具体的存取操作性能有影响。另外这次测试中间改更改过 VM disk的大小,从128GB更改为512GB,但没有发现任何性能变化。也许当thin provision被关闭之后,更改大小也会影响性能。

后记

后来又尝试看看Windows虚拟机在读取Samba大文件时候的性能。可是折腾一通之后,不知道为什么,Windows下本地磁盘的写入性能极差,可以几乎卡死,任务管理器上显示hard disk 写入最高也就在 20MB/s。Google一番也没什么答案。大多数人使用Windows VM的时候,对应的Host storage都是 directory,然后使用 QCOW2或者RAW,没有查到关于使用 ZVOL的资料。遂放弃。

另外,记录一下期间用过的一些命令

FIO测试本地文件写入性能

File: write_test.fio

[global]
ioengine=libaio
direct=1
iodepth=32
rw=write
bs=1M
size=40g
numjobs=1
group_reporting

[job1]
directory=/path/to/test/directory

write_test.fio

然后执行

sudo fio write_test.fio

挂载SAMBA share

# make sure install 'cifs-utils' first
# sudo apt-get install cifs-utils

# Then, run this
sudo mount -t cifs -o username=serverUserName //myServerIpAdress/sharename /mnt/myFolder/

# When finished, unmount
# Note: You can't unmount in the mount folder,
# you need to cd out of the mount folder tree first.
# Note 2: the command is 'umount', not 'unmount'.
cd ~
sudo umount <path_to_the_mount_folder>

检查RAID Stride 和 Stripe 的设定

# Note, you may need to install it first with apt-get

# /dev/sda2 is supposed to be the partition of your root system
# Change it accordingly, e.g. on Xubuntu, it is /dev/sda3
sudo tune2fs -l /dev/sda2

胡思乱想

  • 总觉得 Proxmox上面的ZFS设定有点奇怪。在其上创建的ZVOL上面跑VM总觉得很难得到想要的Disk IO的性能。之前在Proxmox默认创建的rpool 上面跑VM,即使是使用SSD ZFS mirror的情况下,也能在非常少量的VM内IO的时候,直接把主机卡死(IO delay 达到70左右,整机卡死)。因而我现在只把rpool当作Proxmox启动自己专用的系统盘,而不敢在上面跑VM。
💡
消费级SATA SSD 组VM pool的性能测试详见后续文章
  • Proxmox自然是要挣钱的,而企业方现在可能真的会大规模用的方案,应该是更多的使用Proxmox在超融合方面的能力,以及对于SAN的支持。对于生产环境而言,也许根本就不会有VM跑在本地的ZVOL上面。要不就是Ceph走超融合,要不就是iSCSI通过SAN来提供VM的存储。两者都能提供足够的冗余,并满足生产环境对于可迁移性的要求。本地跑ZVOL算是怎么回事,完全就是玩票的搞法。
  • 并且考虑之前在Proxmox上面组HDD的 ZFS mirror 10的经验,TrueNAS的对于ZFS就专注很多。目前来看,性能表现上面,也一直是比较符合理论预期的。比较可惜的一点是,TrueNAS如果反过来再给主机Proxmox提供storage(尤其是iSCSI),则容易陷入因为挂载没有关闭,而无法关闭TrueNAS,进而Proxmox也在该关机的时候无法关机的陷阱。虽然有hook script可以解决一部分问题,但是既然是anti-pattern,那就不要这样做好了。之后考虑的方案可能就是 Application 的 VM 和 Infra 的VM分开在两个物理机上。Infra 的 物理机负责 TrueNAS,OPNsense,以及Backup的处理,主要就是提供大容量存储和网络(DNS, DHCP, Firewall)的需求。理论上这个 Infra 物理机也应该提供 SAN 的支持,或者至少是 iSCSI的服务。但是因为我现在没有10Gbe,所以大概没有太大必要这么做?而Application的主机就是跑各种应用服务以及 docker,甚至尝试 k8s 了。现在一个麻烦的地方就是,我现在手头的主板只有一个Asus B460M,只有一个PCIE x16和两个 PCIE x1。保留 PCIE x16给显卡的情况下,没有办法再接 10Gbe,所以暂时先搁置这个 Infra/Application 分开的方案。