30.6 ZFS 调优
30.6.1 技术潜能与现实困境
ZFS 的性能优势与高级特性需要针对性的参数调优才能充分发挥,调优策略依赖具体环境,需结合存储硬件、工作负载特征与使用场景作个性化配置,主要调优方向包括 ARC 缓存大小、记录大小、压缩算法选择等。ZFS 不属于典型的开箱即用型文件系统。
30.6.2 调优
调整可调参数,使 ZFS 在不同的工作负载下表现最佳。可以随时通过 sysctl(8) 调整以下值,还可以在 /boot/loader.conf 或 /etc/sysctl.conf 中永久设置某值。
vfs.zfs.arc.max- ARC 的最大大小。默认值为0,对于 FreeBSD,实际取总内存 - 1 GiB 与总内存的 5/8 中的较大值。此值不得低于 64 MiB。如果系统运行其他守护进程或进程可能需要内存,可以使用较小的值。注意
可以使用 sysctl(8) 动态修改
vfs.zfs.arc.max。但是系统运行期间无法再将其改回0;此外,若将该设定值调得比当前 ARC 实际占用还低,ARC 将不会主动缩减,必须等到系统出现内存压力时才会触发回收。vfs.zfs.arc.min- ARC 的最小大小。默认值为0,实际取 32 MiB 与总内存的 1/32 中的较大值。可以调整此值,以防止其他应用程序挤出整个 ARC。vfs.zfs.vdev.min_auto_ashift- 池创建时自动使用的最低ashift(扇区大小)。该值是 2 的幂。默认值为9,表示2^9 = 512,即 512 字节的扇区大小。为了避免 写放大 并获得最佳性能,应将此值设置为池中设备使用的最大扇区大小。常见的驱动器有 4 KB 扇区。使用默认的ashift值9与这些驱动器会导致写放大。在这些设备中,单个 4 KB 写入的数据将以八次 512 字节写入的方式写入。ZFS 尝试在创建池时从所有设备读取原生扇区大小,但具有 4 KB 扇区的驱动器为兼容性考虑报告其扇区为 512 字节。在创建池之前将vfs.zfs.vdev.min_auto_ashift设为12(2^12 = 4096),即可强制 ZFS 使用 4 KB 块,从而获得最佳性能。技巧
通过 bsdinstall 安装的 FreeBSD ZFS 系统,
vfs.zfs.vdev.min_auto_ashift值默认为12,参见源代码文件 usr.sbin/bsdinstall/scripts/zfsboot。强制使用 4 KB 块在计划升级磁盘的池中也非常有用。目前的磁盘使用 4 KB 扇区,而
ashift值在创建池后无法更改。在某些特定情况下,较小的 512 字节块大小可能更为合适。例如,在使用 512 字节磁盘用于数据库或虚拟机存储时,较小的块在小随机读取时会传输更少的数据。这可以在使用较小的 ZFS 记录大小时提供更好的性能。
vfs.zfs.prefetch.disable- 禁用预测性预取。值为0时启用,值为1时禁用。默认值为0(启用预测性预取)。预取会将比请求的块大得多的数据块读取到 ARC 中,预期稍后会用到这些数据。如果工作负载有大量随机读取,禁用预取可能因减少不必要的读取而提高性能。注意,此参数仅禁用预测性预取,不影响先验性预取(prescient prefetch,如zfs send使用的预取),后者永远不会发出最终不被需要的 I/O,因此不会影响性能。vfs.zfs.l2arc.write_max- 限制每个 L2ARC 设备每秒写入的最大数据量。默认值为67108864字节(64 MiB)。总 L2ARC 吞吐量随池中缓存设备数量线性增长。vfs.zfs.l2arc.noprefetch- 是否将预取但未被应用程序使用的缓冲区写入 L2ARC。默认值为1(禁用)。值为0时启用。禁用时,预取的数据不会缓存到 L2ARC。将此值设为0可将磁盘上的顺序读取缓存到 L2ARC,并在之后从 L2ARC 提供这些读取服务。当 L2ARC 设备在顺序读取上比池磁盘快得多时,这可能是有益的。vfs.zfs.l2arc.mfuonly- 控制从 ARC 缓存到 L2ARC 的内容。默认值为0,表示 MRU 和 MFU 的数据和元数据都会被缓存到 L2ARC。设为1时,仅缓存 MFU 数据和元数据,适用于读写大量不会再次访问的数据时避免浪费 L2ARC 空间的场景。设为2时,缓存所有元数据(MRU+MFU)但仅缓存 MFU 数据,适用于希望在数据高周转时尽可能多地缓存元数据的场景。vfs.zfs.l2arc.dwpd_limit- L2ARC 设备的每日写入量(Drive Writes Per Day)限制,以百分比表示,默认值为100。100等于 1.0 DWPD,即每个 L2ARC 设备每天最多写入自身容量一次。较低的值支持分数 DWPD(50 = 0.5 DWPD,30 = 0.3 DWPD,适用于 QLC SSD)。较高的值允许更多写入(300 = 3.0 DWPD)。实际写入速率始终受vfs.zfs.l2arc.write_max限制。值为0时禁用 DWPD 速率限制。DWPD 限制仅在初始填充阶段完成且 L2ARC 总容量至少为arc_c_max的两倍后才生效。vfs.zfs.txg.timeout- 事务组(transaction group)之间的最大秒数,即脏数据刷写到磁盘的最大间隔。默认值为5秒。当前事务组写入池中,如果自上一个事务组以来经过了此时间,则启动新的事务组。如果写入了足够的数据,事务组可能会提前触发。较大的值可能因延迟异步写入而提高读取性能,但这可能导致写入事务组时性能不均匀。vfs.zfs.vdev.scrub_min_active- scrub 操作时每个设备的最小并发 I/O 数。默认值为1。当 vdev 空闲时,并发数自动提升至vfs.zfs.vdev.scrub_max_active。vfs.zfs.vdev.scrub_max_active- scrub 操作时每个设备的最大并发 I/O 数。默认值为3。增大此值可加快 scrub 完成速度,但会增加读写延迟并降低吞吐量。vfs.zfs.vdev.rebuild_min_active- sequential rebuild(顺序重建,区别于传统 resilver)操作时每个设备的最小并发 I/O 数。默认值为1。vfs.zfs.vdev.rebuild_max_active- sequential rebuild 操作时每个设备的最大并发 I/O 数。默认值为3。增大此值可加快 rebuild 完成速度,但会增加读写延迟。vfs.zfs.vdev.nia_delay- 对于非交互式 I/O(scrub、resilver、移除、初始化和重建),并发 I/O 数限制为各队列的min_active,除非 vdev 处于“空闲”状态。当没有交互式 I/O 活动,且自上次交互式操作以来已完成vfs.zfs.vdev.nia_delay个非交互式操作后,vdev 被视为“空闲”,非交互式操作的并发数提升至各队列的max_active。默认值为5。vfs.zfs.vdev.nia_credit- 某些机械硬盘会以较高优先级处理顺序 I/O,导致并发随机 I/O 延迟达到数秒。为防止非交互式 I/O(如 scrub)独占设备,当存在未完成的交互式 I/O 时,最多只能发送vfs.zfs.vdev.nia_credit个非交互式操作。此强制等待确保机械硬盘在合理时间内处理交互式 I/O。默认值为5。
30.6.3 参考文档
与 ZFS 调优相关的文档包括:
- OpenZFS 项目的官方文档 https://openzfs.github.io/openzfs-docs/index.html,其中包含专门的性能与调优章节,涵盖模块参数、工作负载调优等内容。
- 《FreeBSD 操作系统设计与实现(第二版)》:包含 ZFS 原理性描述。
- FreeBSD Mastery: ZFS 与 FreeBSD Mastery: Advanced ZFS:价值有限。
- Oracle Solaris 管理:ZFS 文件系统:该文档在 OpenZFS 项目启动之前撰写,不包含 OpenZFS 近十五年来的开发进展,仅供参考。