我在尝试备份 zfs 文件系统时遇到了奇怪的性能问题。
我可以以 100+ MB/s 的速度压缩 zfs 文件系统的内容,但 zfs send 的传输速度可能为 5 MB/s。文件系统只有 5 或 6 个快照。一个 tar 大约需要 1.5 小时。一次 zfs 发送需要 12 个小时以上!
在这两种情况下,目标都是另一个池上的文件。 (即zfs send tank/myfs > /backup/myfs.zfsbackup
vs. tar -cf /backup/myfs.tar ./myfs
)
我的第一个想法是碎片化,但如果是这样的话,tar 不也一样慢吗?
我的整体磁盘性能已经足够不错,但我的备份实际上需要很长时间。
我在 x64 硬件上运行 Solaris 11.4。从概念上讲,这个问题可能与 Linux 上的 zfs 类似,但我对 Linux 变体不太熟悉。
当 zfs send 运行时,我运行了下面答案中提供的 dtrace 脚本大约 12 分钟。
dtrace -i 'profile:::profile-1001hz /arg0/ { @[ stack() ] = count(); }'
我不知道如何解释结果。摘要的两个部分包含大量 zfs 调用:
zfs`zfs_fletcher_4_native+0x79
zfs`zfs_checksum_compute+0x181
zfs`zio_checksum_compute+0x1d6
zfs`zio_checksum_compute_dispatch+0x28
zfs`zio_checksum_generate+0x59
zfs`zio_execute+0xb4
genunix`taskq_thread+0x3d5
unix`thread_start+0x8
1041
unix`bcopy+0x55a
genunix`uiomove+0xb3
zfs`dmu_xuio_transform+0x83
zfs`zfs_write+0x78a
genunix`fop_write+0xf5
genunix`vn_rdwr_impl+0x1f3
genunix`vn_rdwr_uiov+0x63
zfs`dump_buffer_flush+0x8e
zfs`dump_buffer_append+0x85
zfs`dump_bytes_impl+0x49
zfs`dump_bytes+0x49
zfs`dump_record+0x190
zfs`dump_data+0x26a
zfs`backup_cb+0x4b5
zfs`traverse_visitbp+0x3df
zfs`traverse_visitbp+0x8e4
zfs`traverse_visitbp+0x8e4
zfs`traverse_dnode+0x1dc
zfs`traverse_visitbp+0x6d2
zfs`traverse_visitbp+0x8e4
1183
最高数量的调用似乎是 cpu 空闲调用......
unix`mach_cpu_idle+0x17
unix`cpu_idle+0x2b7
unix`cpu_idle_adaptive+0x19
unix`idle+0x11e
unix`thread_start+0x8
1147665
unix`mach_cpu_idle+0x17
unix`cpu_idle+0x2b7
unix`cpu_idle_adaptive+0x19
unix`idle+0x11e
unix`thread_start+0x8
2462890
在 zfs 发送期间,驱动器很忙,但没有任何等待,我认为服务时间并没有那么糟糕......
extended device statistics
r/s w/s Mr/s Mw/s wait actv wsvc_t asvc_t %w %b device
157.0 0.0 4.9 0.0 0.0 1.6 0.0 10.5 0 77 c0t5000C500A22D9330d0
154.0 0.0 4.9 0.0 0.0 1.7 0.0 11.0 0 82 c0t5000C500A232AFA6d0
186.0 0.0 6.4 0.0 0.0 2.4 0.0 12.7 0 93 c0t5000C500A24AD833d0
185.0 0.0 6.3 0.0 0.0 1.8 0.0 9.9 0 79 c0t5000C500A243C8DEd0
在 tar 期间,磁盘使用情况似乎相当相似......即 r/s、服务时间、%busy 等,但读取的数据量却截然不同:
extended device statistics
r/s w/s Mr/s Mw/s wait actv wsvc_t asvc_t %w %b device
158.0 0.0 33.3 0.0 0.0 1.9 0.0 11.9 0 86 c0t5000C500A22D9330d0
190.0 0.0 31.9 0.0 0.0 1.6 0.0 8.3 0 75 c0t5000C500A232AFA6d0
170.0 0.0 37.1 0.0 0.0 1.7 0.0 9.7 0 80 c0t5000C500A24AD833d0
168.0 0.0 38.4 0.0 0.0 1.7 0.0 10.1 0 80 c0t5000C500A243C8DEd0
答案1
当您运行zfs send ...
命令时,您可以运行此 dTrace 命令来查看内核将时间花在哪里:
dtrace -i 'profile:::profile-1001hz /arg0/ { @[ stack() ] = count(); }'
以 启动该命令root
,让它运行一段时间,点击CTRL-C
停止它,它将按数字递增的顺序发出它采样的所有内核堆栈跟踪。
因此找到的最常见的堆栈跟踪将是最后一个。这将是你的内核花费大部分时间的地方。
这些信息可能有帮助,也可能没有帮助。
或者,您可以将其保存在如下文件中:
#!/usr/sbin/dtrace -s
profile:::profile-1001hz
/arg0/
{
@[ stack() ] = count();
}
自从 dTrace 首次出现在 Solaris 10 上以来,我就一直在使用这个小脚本。它可能是我遇到过的最有用的单个 dTrace 脚本,因为它告诉您“系统实际上在做什么?”这个问题的答案。