zfs 未使用完整磁盘 I/O

zfs 未使用完整磁盘 I/O

我已经在全新的 Ubuntu 20.04 上设置了 zfs。但速度似乎非常慢。

如果并行运行,这些磁盘可以提供 140 MB/s 的速度:

$ parallel -j0 dd if={} of=/dev/null bs=1M count=1000 ::: /dev/disk/by-id/ata-WDC_WD80E*2
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 7.23989 s, 145 MB/s
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 7.34566 s, 143 MB/s
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 7.39782 s, 142 MB/s
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 7.43704 s, 141 MB/s
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 7.90308 s, 133 MB/s

$ iostat -dkx 1 
Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz  aqu-sz  %util
loop0            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
loop1            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
loop2            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
loop3            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
sda            214.00 136112.00    11.00   4.89    5.97   636.04    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.84  89.60
sdb            216.00 145920.00     0.00   0.00    5.71   675.56    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.77  92.40
sdc            216.00 147456.00     0.00   0.00    5.55   682.67    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.73  92.80
sdd            199.00 135168.00     0.00   0.00    5.77   679.24    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.73  88.40
sde            198.00 133120.00     0.00   0.00    5.82   672.32    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.75  88.00

因此原始并行性能约为 700 MBytes/s。这是受 CPU 限制的,而不是磁盘 I/O。如果不并行运行,每个磁盘可以提供 170 MB/s。

如果我使用磁盘构建 RAID5:

$ mdadm --create --verbose /dev/md0 --level=5 --raid-devices=5 /dev/disk/by-id/ata-WDC_WD80E*2
# To stop the initial computing of parity:
$ echo frozen > /sys/block/md0/md/sync_action
$ echo 0 > /proc/sys/dev/raid/speed_limit_max
$ dd if=/dev/md0 of=/dev/null bs=1M count=10k
10240+0 records in
10240+0 records out
10737418240 bytes (11 GB, 10 GiB) copied, 40.3711 s, 266 MB/s

$ iostat -dkx 1
Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz  aqu-sz  %util
loop0            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
loop1            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
loop2            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
loop3            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
md0            264.00 270336.00     0.00   0.00    0.00  1024.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
sda              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
sdb            134.00  68608.00 16764.00  99.21    5.48   512.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.54  73.20
sdc            134.00  68608.00 16764.00  99.21    5.56   512.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.54  74.00
sdd            134.00  68608.00 16764.00  99.21    5.65   512.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.54  74.00
sde            134.00  68608.00 16764.00  99.21    5.84   512.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.54  74.80
sdf              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00

这比 700 MBytes/s 还差。top表示该过程md0_raid5占用了 80% 的核心,dd占用了 60%。我看不出瓶颈在哪里:磁盘没有 100% 繁忙,CPU 也没有。

在相同的 5 个磁盘上我创建了一个 zfs 池:

zpool create -f -o ashift=12 -O acltype=posixacl -O canmount=off -O dnodesize=auto -O normalization=formD -O relatime=on -O xattr=sa rpool raidz /dev/disk/by-id/ata-WDC_WD80E*2
zfs create -o mountpoint=/data rpool/DATA

然后我写一些数据:

$ seq 100000000000 | dd bs=1M count=10k iflag=fullblock > out
10240+0 records in
10240+0 records out
10737418240 bytes (11 GB, 10 GiB) copied, 91.2438 s, 118 MB/s

$ iostat -dkx 1
Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz  aqu-sz  %util
loop0            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
loop1            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
loop2            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
loop3            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
sda              0.00      0.00     0.00   0.00    0.00     0.00   79.00  27460.00     8.00   9.20   15.99   347.59    0.00      0.00     0.00   0.00    0.00     0.00    1.12  36.00
sdb              0.00      0.00     0.00   0.00    0.00     0.00  113.00  25740.00     0.00   0.00    9.73   227.79    0.00      0.00     0.00   0.00    0.00     0.00    0.88  38.00
sdc              2.00      0.00     0.00   0.00    2.50     0.00  319.00  25228.00     2.00   0.62    1.68    79.08    0.00      0.00     0.00   0.00    0.00     0.00    0.28  31.20
sdd              0.00      0.00     0.00   0.00    0.00     0.00  111.00  25872.00     0.00   0.00   10.87   233.08    0.00      0.00     0.00   0.00    0.00     0.00    0.96  40.00
sde              0.00      0.00     0.00   0.00    0.00     0.00  109.00  26356.00     0.00   0.00   10.74   241.80    0.00      0.00     0.00   0.00    0.00     0.00    0.93  40.80
sdf              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00

z_wr_iss 使用 30% 的 CPU。

当我读回数据时:

$ pv out >/dev/null
10.0GiB 0:00:44 [ 228MiB/s]

$ iostat -dkx 1
Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz  aqu-sz  %util
loop0            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
loop1            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
loop2            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
loop3            0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00
sda           1594.00  51120.00     5.00   0.31    0.25    32.07    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00 100.40
sdb           1136.00  36312.00     0.00   0.00    0.20    31.96    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00  96.40
sdc           1662.00  53184.00     0.00   0.00    0.20    32.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00 100.00
sdd           1504.00  48088.00     0.00   0.00    0.19    31.97    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00  99.60
sde           1135.00  36280.00     0.00   0.00    0.21    31.96    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00  99.20
sdf              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00

iostat -dkx 1表示磁盘 I/O 利用率为 100%。top表示pv使用大约 60% 的 CPU 和zthr_procedure大约 30% 的 CPU。使用 2 个核心时,会有一个核心处于空闲状态。

这让我很惊讶:如果我获得 700 MB/s 的原始并行读取性能,我预计 zfs 也可以利用这一点,并且受到 CPU 的限制(可能给出 300 MB/s 的数量级)。

我唯一的猜测是,如果zfs使用较小的条带大小或块大小,并强制驱动器经常刷新缓存。但这在阅读时几乎没有意义。

为什么iostat -dkx 1说使用 zfs 时磁盘的 I/O 利用率是 100%,而每个磁盘的 I/O 仅为 40 MBytes/s?我能否以 zfs 更好地利用磁盘 I/O 的方式重新创建池?

答案1

这是一个老问题,但值得回答。

首先,从多个磁盘并行连续读取绝对是最佳情况:您完全没有争用,并且每个磁盘都提供大量连续 IO。因此,将其视为绝对限制,但不要期望真正达到它。

创建 RAID5 阵列时,现代的默认块大小mdadm为 512K,与默认的最大 IO 段大小相同。这意味着发出的单个顺序读取dd将一次访问单个磁盘,而 Linux 预取(最终)将访问更多磁盘。这通常是一件好事:由于机械硬盘通常受延迟而非带宽限制,因此不浪费多个 IO 进行单次读取是一种优势。多个并发顺序读取(如发布的那样fio --bs=1M --rw=read --numjobs=16)将使用整个阵列带宽,但简单的dd(以队列深度 1 运行)不会捕捉到这种效果。

如果您确实需要最大顺序 IO 且队列深度低至 1,则需要大大增加预取限制(例如:通过发出某些内容blockdev --setra 8192),并且可能将数组块大小降低到 ~64K。

但这样做会影响最重要的性能——随机和/或并发 IO。因此请谨慎使用,不要dd单独依赖它来进行性能调整。

对于 ZFS 来说同样适用,但有一些区别:

  • 您需要调整的是 ,而不是块大小recordsize。默认值为 128K,这是一个很好的中间值,但对于存储大文件,可以使用 1M;

  • 预取是通过zfetch_max_distance模块可调参数控制的。默认值为 8M,这对于大多数小型 HDD 阵列来说完全没问题,但您可以增加它以进行测试。

再次,不要盲目优化简单的低队列顺序读取,除非你确定你的工作负载严重依赖于它们

相关内容