单个磁盘上的 ZFS 读取行为

单个磁盘上的 ZFS 读取行为

由于 ZFS 具有出色的压缩和快照功能,我尝试在单个磁盘上设置它。我的工作负载是 Postgres 服务器。常用指南建议以下设置:

atime = off
compression = lz4
primarycache = metadata
recordsize=16k

但是通过这些设置,我确实看到读取速度有些奇怪 - 我只是在看这个!

作为参考,这是我使用 XFS 的测试驱动器(Intel P4800X),这是使用 dd 进行的简单直接 IO 测试:

 [root@at-storage-01 test]# dd if=large_file.bin of=/dev/zero bs=4K iflag=direct
 910046+0 records in
 910046+0 records out
 3727548416 bytes (3.7 GB) copied, 10.9987 s, 339 MB/s
 [root@at-storage-01 test]# dd if=large_file.bin of=/dev/zero bs=8K iflag=direct
 455023+0 records in
 455023+0 records out
 3727548416 bytes (3.7 GB) copied, 6.05091 s, 616 MB/s
 [root@at-storage-01 test]# dd if=large_file.bin of=/dev/zero bs=16K iflag=direct
 227511+1 records in
 227511+1 records out
 3727548416 bytes (3.7 GB) copied, 3.8243 s, 975 MB/s
 [root@at-storage-01 test]# dd if=large_file.bin of=/dev/zero bs=32K iflag=direct
 113755+1 records in
 113755+1 records out
 3727548416 bytes (3.7 GB) copied, 2.78787 s, 1.3 GB/s
 [root@at-storage-01 test]# dd if=large_file.bin of=/dev/zero bs=64K iflag=direct
 56877+1 records in
 56877+1 records out
 3727548416 bytes (3.7 GB) copied, 2.18482 s, 1.7 GB/s
 [root@at-storage-01 test]# dd if=large_file.bin of=/dev/zero bs=128K iflag=direct
 28438+1 records in
 28438+1 records out
 3727548416 bytes (3.7 GB) copied, 1.83346 s, 2.0 GB/s
 [root@at-storage-01 test]# dd if=large_file.bin of=/dev/zero bs=256K iflag=direct
 14219+1 records in
 14219+1 records out
 3727548416 bytes (3.7 GB) copied, 1.69168 s, 2.2 GB/s
 [root@at-storage-01 test]# dd if=large_file.bin of=/dev/zero bs=512K iflag=direct
 7109+1 records in
 7109+1 records out
 3727548416 bytes (3.7 GB) copied, 1.54205 s, 2.4 GB/s
 [root@at-storage-01 test]# dd if=large_file.bin of=/dev/zero bs=1M iflag=direct
 3554+1 records in
 3554+1 records out
 3727548416 bytes (3.7 GB) copied, 1.51988 s, 2.5 GB/s

如您所见,驱动器在 4K 读取时可以达到约 80k IOPS,在 8K 读取时也是如此 - 这里呈线性增长(根据规格,它可以在 QD16 时达到 550k IOPS,但我在这里测试单线程顺序读取 - 所以一切都符合预期)

zfs 的内核参数:

options zfs zfs_vdev_scrub_min_active=48
options zfs zfs_vdev_scrub_max_active=128
options zfs zfs_vdev_sync_write_min_active=64
options zfs zfs_vdev_sync_write_max_active=128
options zfs zfs_vdev_sync_read_min_active=64
options zfs zfs_vdev_sync_read_max_active=128
options zfs zfs_vdev_async_read_min_active=64
options zfs zfs_vdev_async_read_max_active=128
options zfs zfs_top_maxinflight=320
options zfs zfs_txg_timeout=30
options zfs zfs_dirty_data_max_percent=40
options zfs zfs_vdev_scheduler=deadline
options zfs zfs_vdev_async_write_min_active=8
options zfs zfs_vdev_async_write_max_active=64

现在使用 ZFS 和 16K 的块大小进行相同的测试:

 910046+0 records in
 910046+0 records out
 3727548416 bytes (3.7 GB) copied, 39.6985 s, 93.9 MB/s
 455023+0 records in
 455023+0 records out
 3727548416 bytes (3.7 GB) copied, 20.2442 s, 184 MB/s
 227511+1 records in
 227511+1 records out
 3727548416 bytes (3.7 GB) copied, 10.5837 s, 352 MB/s
 113755+1 records in
 113755+1 records out
 3727548416 bytes (3.7 GB) copied, 6.64908 s, 561 MB/s
 56877+1 records in
 56877+1 records out
 3727548416 bytes (3.7 GB) copied, 4.85928 s, 767 MB/s
 28438+1 records in
 28438+1 records out
 3727548416 bytes (3.7 GB) copied, 3.91185 s, 953 MB/s
 14219+1 records in
 14219+1 records out
 3727548416 bytes (3.7 GB) copied, 3.41855 s, 1.1 GB/s
 7109+1 records in
 7109+1 records out
 3727548416 bytes (3.7 GB) copied, 3.17058 s, 1.2 GB/s
 3554+1 records in
 3554+1 records out
 3727548416 bytes (3.7 GB) copied, 2.97989 s, 1.3 GB/s

如您所见,4K 读取测试的最大速度已达到 93 MB/s,8K 读取速度达到 184 MB/s,16K 达到 352 MB/s。根据之前的测试,我肯定会期望 4k (243.75)、8k (487.5)、16k (975) 的读取速度更快。此外,我读到记录大小对读取性能没有影响 - 但显然它有影响。

为了比较 128k 记录大小:

910046+0 records in
910046+0 records out
3727548416 bytes (3.7 GB) copied, 107.661 s, 34.6 MB/s
455023+0 records in
455023+0 records out
3727548416 bytes (3.7 GB) copied, 55.6932 s, 66.9 MB/s
227511+1 records in
227511+1 records out
3727548416 bytes (3.7 GB) copied, 27.3412 s, 136 MB/s
113755+1 records in
113755+1 records out
3727548416 bytes (3.7 GB) copied, 14.1506 s, 263 MB/s
56877+1 records in
56877+1 records out
3727548416 bytes (3.7 GB) copied, 7.4061 s, 503 MB/s
28438+1 records in
28438+1 records out
3727548416 bytes (3.7 GB) copied, 4.1867 s, 890 MB/s
14219+1 records in
14219+1 records out
3727548416 bytes (3.7 GB) copied, 2.6765 s, 1.4 GB/s
7109+1 records in
7109+1 records out
3727548416 bytes (3.7 GB) copied, 1.87574 s, 2.0 GB/s
3554+1 records in
3554+1 records out
3727548416 bytes (3.7 GB) copied, 1.40653 s, 2.7 GB/s

我还可以通过 iostat 清楚地看到磁盘的平均请求大小与相应的记录大小相同。但 IOPS 远低于 XFS。

它应该这样表现吗?这种行为记录在哪里?我需要我的 postgres 服务器具有良好的性能(顺序 + 随机),但我也希望我的备份、复制等(顺序)具有出色的性能 - 因此,似乎我要么使用大记录获得良好的顺序速度,要么使用小记录获得良好的随机速度。

编辑:此外,我还测试了 primarycache=all,结果发现更加奇怪,因为无论记录大小,它的最大速度都为 1.3 GB/s。

服务器详细信息:

64 GB DDR4 内存
英特尔至强 E5-2620v4
英特尔 P4800X

答案1

观察到的行为是由于 ZFS 如何进行端到端校验和,它基于记录大小概念。

基本上,每个对象被分解成适当数量的记录大小的块,这些块分别进行校验和。这意味着小于记录大小的读取确实需要传输并重新校验所有的记录大小的对象,导致“浪费”存储带宽。

这意味着大记录大小的 ZFS 数据集在小读取时表现不佳,相反,在大读取时表现良好。相反,小记录大小的 ZFS 数据集在小读取时表现良好,在大读取时表现不佳。

请注意,压缩和快照也适用于记录大小粒度:记录大小为 4K 或 8K 的数据集的压缩率将比 32K 数据集低得多。

简而言之,ZFS recordsize 没有“万无一失”的值,您需要根据特定应用程序的要求进行调整。这也意味着它dd不是基准测试的良好选择(尽管它既快速又粗糙,我也广泛使用它!);相反,您应该使用fio(调整为与您的应用程序一样运行)或应用程序本身。

你可以阅读这里了解更多信息。

对于一般用途,我会将其保留为默认值(128K),而对于数据库和虚拟机,我会使用小得多的 32K 值。

最后,注意 ZFS 预读/预取调整,这可以显著提高读取速度。

相关内容