年初时候重新开始折腾服务器,确定了用Proxmox做主机,TrueNAS Scale 存Data的方式,构建整个服务器的架构。又因为心水ZFS mirror几乎“免费“的高可用能力,义无反顾的又一次上了ZFS车。但是因为ZFS的写入放大,以及有时表现出来的不稳定的性能,心里总是不踏实。看了众多的资料之后,决定还是趁着refactor的机会,自己做一次测试,看看问题究竟有多夸张。

背景信息 | Context

Proxmox和TrueNAS社区都是非常不建议用消费级的SSD的,而对于HDD,因为ZFS基本上会让硬盘保持一直运行的状态,所以最好也是企业级的硬盘。可以说,即使用Proxmox+TrueNAS的初衷只是一个小作坊级别的Server,但是因为workload的特性跟一个正常Server不会有什么区别,所以总还是上企业级好一些。Proxmox对于消费级SSD的抵制,实际上更甚于TrueNAS对于ECC的抵制。

但是消费级SSD究竟能有多糟糕,对于小作坊的场景真就不能用吗?网上的信息林林总总,总归跟自己的情况不一样,有时也是婆说婆有理公说公有理,很难做出准确的判断。

一个比较确切的测试是来自Proxmox,关于ZFS + NVME性能的一个文档

重要的部分截取如下: 磁盘直写性能比较 - 截取自Proxmox-VE_ZFS-Benchmark-202011.pdf

磁盘直写性能测试命令 - 截取自Proxmox-VE_ZFS-Benchmark-202011.pdf

但是这里的测试结果实际上跟ZFS无关。这个FIO command 测试的是直写性能,而且似乎也不是random的,但是确实是sync+4K。所以参考价值还是很高的。可惜的是,这个文档并没有测试Samsung 850这类consumer SSD在ZFS上面的表现。我们穷人还是不知道consumer SSD在ZFS上面,一个合理的performance expectation大体是个什么程度。当然从这个结果我们已经可以看到消费级(Samsung 850)和企业级的巨大差别(Intel DC S3500)了。

测试环境 | Setup

主机系统是Proxmox 7.4,CPU是i5 7600k,RAM:64GB,其中16GB给到了TrueNAS Scale虚拟机。主板是历久弥新的Gigabyte z270p。虽然是旧平台了,但是老平台接口全啊(3个PCIEx16物理插槽,3个PCIEx1物理插槽,可惜只有一个NVME,最大也只有64GB内存)。

zfs version:

  • zfs-2.1.6-pve1
  • zfs-kmod-2.1.6-pve1

TrueNAS VM直通了一个SATA expansion card,上面接了一个Seagate EXOS 14TB和一个 WD EDGZ 白标拆机 14TB,两个应该都可以算是企业级HDD,组成ZFS Mirror。TrueNAS VM只给了2个CPU Core。

  • Version: TrueNAS-SCALE-22.12.0
  • ARC max size: <8GB (by default arc is 50% of the system memory for TrueNAS Scale as it is on Linux)

另外手上可以用来测试的SSD:

  • Crucial M500 480GB。一个相当早的SSD了,但是这种早期的SSD是被ZFS认为带有Power Lost Protection (PLP)的(详见这里)。所以给ZFS用还有可能是比现在的SSD更好的选择。
  • Crucial MX500 512GB。一个现在被认为在SATA SSD品类里面不会错的选择。作为消费级标杆(i.e. 比上不足比下有余)非常合适。
  • ADATA LEGEND 850 2TB PCIE 4.0 NVME。一个PCIE 4.0中速NVME。对于NVME,受限于主板的pcie 3.0 m.2接口,我们这里只做大体上定性的分析,具体说数值很可能不是很有参考性。

这里有几个地方肯定是犯了众怒的,但是有限于条件,只能将就了。

  • Memory不是ECC。不过这个应该不影响性能。
  • 两个HDD是接在SATA Expansion card上面,而不是正经HBA card。而且SATA expansion card还是接在pcie 3.0 x1的接口上。此处的安排并不推荐。但是个人用下来目前没有什么问题。pcie 3.0 x1的接口速度对于两个HDD来讲还是够的,大体上到4块HDD的时候才有一点点可能出问题。
  • TrueNAS是VM。依旧不推荐这个安排,但是对于家用以及小作坊,个人认为也是可以的。只要确保硬盘是通过PCI控制器直通进TrueNAS就行。而且仅限于偏向AIO的架构方案,如果要严肃一点的话,VM和Data还是物理上分离为好,或者彻底做HCI方案亦可。

测试会偏向于4K的测试,因为之前在使用这两个SATA SSD作为VM的storage时,观察到性能非常令人失望,所以才有的这个测试。具体就是要看看小文件写入上面的区别。

测试会采用如下命令

fio --filename=test --sync=1 --rw=randwrite --bs=4k \
	--numjobs=1 --iodepth=<qd> --group_reporting \
    --name=test --filesize=10G --runtime=<time>
  • qd: 1, 16, 32
  • time: 300 seconds or 60 seconds 主要是300太长了,等不及了。

测试会对比一下,2个HDD组成ZFS mirror的情况,然后看看2个sata SDD组成 ZFS mirror的情况,相比HDD孰优孰劣。之后看看NVME能有多大的提高。因为手上只有一个NVME,主板上也只有一个m.2接口,所以NVME就没有办法mirror了。

NVME的单盘ZFS性能测试和HDD ZFS Mirror是在TrueNAS之下做的。而M500+MX500的 ZFS mirror是在Proxmox下面做的。测试时NVME里面大概有100G的数据,HDD里面有1TB数据,M500/MX500里面有300G数据(这个比例对于480G的总空间来讲算是比较多的了)

而后NVME被从TrueNAS中取出(实际上是NVME的Controller直通被取消),然后在Proxmox上面组LVM Thin,用来支持LXC。之后创建了一个Ubuntu 22.04的LXC,分配592GB的空间,在这个LXC里面运行fio进行写入测试。

测试与结果 | Tests and Results

除非特殊说明,测试都采用 job=1的参数,所以测试结果并不是这个硬盘的最大性能。应该说,目的就不是最大性能,而是看看对于单纯的一个写入磁盘的操作,性能差别能有多大。(而且我总是怀疑这个job和queue depth是不是有重叠。)

4K同步写入测试

4K SYNC RANDWRITE - AVG IOPSQD1QD16QD32
NVME 1-disk ZFS noatime2,0582,0962,057
HDD 2-disk ZFS Mirror noatime849662
M500/MX500 2-disk ZFS Mirror noatime654546
NVME LVM-Thin 592G First time1,072--
NVME LVM-Thin 592G Second time1,726--
NVME LVM-Thin 592G - noatime first time2,139--
NVME LVM-Thin 592G - noatime second time2,628-2,702

若不是亲眼所见,真的很难相信M500+MX500的性能可以差到这个程度。这个羸弱的IOPS性能导致在其上运行的任何VM都会比蜗牛还慢。没有想到的是,这个成绩比HDD都要慢,就算是SSD空间占用有点多了,也未曾想到可以差到这个程度。可能是磁盘本身的fragmentation程度已经比较差了。不过后续的测试告诉我们可能不是这样的。

HDD的性能可以说比较符合预期,磁头的寻址延迟差不多在1ms左右,对应的IOPS就很难超过100。

NMVE的性能无论是ZFS还是LVM thin都算是能用的。我们之前链接中给出的Proxmox的企业级NVME测试结果中,Single Job下的randwrite成绩在2325。可以说我们获得的这个NVME的性能是符合预期的。(至于job=4, job=32的情况,本次没有测试)。

Micro 9300 MAX 3.2TB Performance,此处只看job=1的情况-截取自Proxmox-VE_ZFS-Benchmark-202011.pdf

对于NVME+LVM thin,结果有些奇怪。因为LVM thin有 lazy alloc的特性,所以很可能每次跑的成绩有较大浮动。毕竟我们没有什么好办法控制其空间的回收和分配。比较值得注意的是,对于LXC上面,storage mount选项中noatime。这个选项能够很大的印象sync write的性能。这一点具体的原因我还不是很清楚,因为我理解noatime应该是对于读写的情况影响比较大,但是单独的写入不应该有这个问题才对。也可能是我理解不到位。

值得注意的还有测试过程中的波动性,也就是性能的稳定性

4K SYNC RANDWRITE - STDEVQD1QD16QD32
NVME 1-disk ZFS noatime2422741,331
HDD 2-disk ZFS Mirror noatime423346
M500/MX500 2-disk ZFS Mirror noatime2574448
NVME LVM-Thin 592G First time83--
NVME LVM-Thin 592G Second time856--
NVME LVM-Thin 592G - noatime first time811--
NVME LVM-Thin 592G - noatime second time305-274

从上表可以看出,NVME 1-disk ZFS的稳定性还是不错的,只有QD32多情况下偏高。而HDD的ZFS Mirror相比之下差了很多,反应了磁盘寻址latency的随机性。此处别忘了对比离散程度还要对照各自的mean值。而2-disk ZFS mirror在QD1的这次测试中非常不稳定。后面QD16,QD32表现也很一般,毕竟基础的mean的很低了。实际测试是最低的IOPS可以低到2,简直匪夷所思。NVME在LVM-thin中的表现也很不稳定,可能也是反映了lazy alloc的特性。综合来看,NVME的稳定性好很多。

4K异步写入测试

4K ASYNC RANDWRITE - AVGQD1QD16QD32
NVME 1-disk ZFS noatime8,9599,67814,652
HDD 2-disk ZFS Mirror noatime3,7902,4036,495
M500/MX500 2-disk ZFS Mirror noatime399639885
NVME LVM-Thin 592G - noatime first time122,223--
NVME LVM-Thin 592G - noatime second time205,531179,362212,291

sync=0 之后,各方的数据都有很大的提高,分析如下。

NVME ZFS single disk的性能和NVME LVM-thin开始拉开差距。LVM-thin的性能开始接近NVME厂家宣称的数量级,即数百KIOPS的量级,但是ZFS方面则最多在10K这个量级。但是当时测试时发现TrueNAS(也就是NVME+ZFS的测试)的CPU占用达到80%以上,有可能CPU是瓶颈,所以这个数据结果只能作为参考,很可能不具有实际意义。当然,至少这个性能对于家用或者小作坊,已经很可用了。另外我这里jobs定为1,这个数值增大的话,还是很可能可以极大的提高此处的成绩的。

HDD ZFS Mirror的提升非常明显。这也是为什么ZFS比较推荐用Optane组ZIL的原因,因为如果Sync write性能可以因为ZIL的存在,等同于async write,那么通过阵列组合,HDD也可以获得非常不错的性能。比如24盘位,组4个6盘RAIDZ2。假设磁盘性能好一点(比如EXOS 14TB实际上单盘可以到达8KIOPS的async 4K写入),那么阵列就可以达到32KIOP的性能。这个性能相比于很多SATA SSD 4k sync write性能,已经非常好了,甚至已经超过了一般双SATA SSD RAID0(参考之前提到的Proxmox的测试结果,Intel DC S3510 120GB的4k直写性能是12K)。而想要HDD达到这个效果,需要的只是两个小容量的Optane P950。

很显然,ZFS确实对于大量HDD组RAID的场景有相当好的支持,甚至是硬盘越多,得益越多。从另一个角度想,确实如此,假设有无穷的资源供给无穷可靠性的RAID卡,那么自然是硬盘越多,性能越强。如果有Optane,自然是要用在Sync write上面。而ZFS就是把这一套方案打包,同时用ECC内存和一些CPU开销tradeoff硬件阵列卡。很大程度上是依赖CPU和内存的可靠性。应该说在现在这个技术路线下,是非常合理优秀的取舍。

最后回来看consumer SDD ZFS mirror的表现。可以说是匪夷所思了。如此之差的表现比之HDD mirror差了很多。可以说在这里已经完全没有任何使用这个SSD Pool的必要了。这跟我之前在这个Pool上面跑VM的情况一样,完全不如直接使用HDD的pool来的稳定可靠。使用这个SSD pool时,Proxmox的IO delay经常起飞,如果Proxmox OS 也在这两个SSD上面的话,Proxmox会被整体带崩,无法访问。

为了探寻一下MX500和M500里面究竟是谁造成的这个结果,我又单独测试了两个SSD一次。不过这两次测试时,两个磁盘已经清空了,自然不会受到 fragmentation的影响。

单MX500 ZFS 性能

Test caseminmaxavgstdevsamples
mx500 direct, 4k, sync, QD 1, libaio1,9462,5282,154108119
mx500 single zfs, 4k, sync, QD 11,0721,8201,618180119
mx500 single zfs, 4k, sync ,job 1, QD 1, atime=off9701,8181,597180119
mx500 single zfs, 4k, async ,job 1, QD 1, atime=off9,25634,25425,1545,182119

第一个测试是使用Proxmox benchmark里面提供的直写测试命令得出的。可以看到性能跟Samsung 850之类的是在一个数量级的,可以算是很接近的。

4K的同步写入性能也还是比较正常的,比NVME差,但是确实差距不跨数量级。另外,noatime与否,对性能并没有什么影响。

4K异步随机写入性能好了很多,开始能够达到标称的性能数量级。如果jobs的数量上去的话,大概是能达到宣称的数值(标称应该在90KIOPS)。不过我们要知道,这里肯定有DRAM的作用。受限于时间,就没有再多做测试了。

单M500 ZFS性能

test caseminmaxavgstdevsamples
m500 direct, 4k, sync, QD 1, libaio3823419664119
m500 single zfs, 4k, sync, QD 1622217863119
m500 single zfs, 4k, sync, QD 1, atime=off2822017758119
m500 single zfs, 4k, async, QD 1, atime=off1,44841,2629,08710,872118

整体来讲比MX500差了很多。应该说Consumer SATA SSD在2010-2020这期间还是有进步的吧。我手里的M500和MX500应该都是512MB的DDR3缓存。容量上480GB vs. 512GB,差别并不大。但是在ZFS的性能上的差距很明显。

从结果看,似乎是M500拖了后腿,但是确实M500单盘的性能还是比mirror的表现好,这其中的玄妙目前就很难说清了。可能是因为两个SSD的主控差距太大,放在一起,互相之间反而不兼容?

结论 | Conclusion

  • M500 + MX500组合出来的ZFS完全不可用。可能采用不同时代的SSD组ZFS pool,并不是一个好的选择。而如果采用两个完全一样的SSD,也许结果会很不一样。
  • ZFS在企业级的HDD上面,4k随机写入,表现合理,甚至可以说是优秀。
  • ZFS单盘NVME对NVME的性能可能还是有影响,可能异步写入的性能会导致CPU负载升高。某种程度上反应了目前NVME的性能,导致CPU<>IO之间的性能鸿沟被大大缩小了。以往coding的时候把IO操作当作“Infinite“的逻辑似乎已经不成立了。
  • LVM-thin也是有些性能开销的,如果追求 consistent performance,那LVM-thin + NVME恐怕不是一个好的选择。至于lazy alloc会导致这么大的影响,似乎也可能是因为现在NVME的性能确实大大超过了过去人们的预估。

最终在这个实验结果的指导下,MX500和M500被我拆开,跟更古早的2.5寸笔记本hdd组boot pool去了。毕竟boot drive上面不跑VM,基本上是负载最低的地方了。而VM改成用NVME来跑。VM本身实际上是偏 Ephemeral 的东西,所以哪天如果真的挂了,换个盘从backup上面恢复,或者直接重新create就好了。HDD依旧给TrueNAS做data pool,存 persistent data。

这个测试以及结论还非常不严谨,欢迎各位读者留言讨论。

参考资料 | References

在之前的各种无尽的调试(折磨)中参考了以下资料: