20.6. 高级主题

20.6.1. 调优

调整可调节的因素,使 ZFS 在不同的工作负荷下表现最佳。

  • vfs.zfs.arc_max - ARC 的上限大小。默认是 RAM 的总量减 1GB,或所有 RAM 的 5/8,以多者为准。如果系统上运行的任何其他守护程序或进程可能需要内存,请使用较低的值。用 sysctl(8) 调整运行时中的这个值,并在 /boot/loader.conf/etc/sysctl.conf 中设置它。

  • vfs.zfs.arc_meta_limit - 限制用于存储元数据的 ARC 的数量。默认是 vfs.zfs.arc_max 的四分之一。如果工作负载涉及对大量文件和目录的操作,或频繁的元数据操作,增加这个值将提高性能,代价是 ARC 中拟合的文件数据减少。在运行时用 /boot/loader.conf/etc/sysctl.conf 中的 sysctl(8) 调整这个值。

  • vfs.zfs.arc_min - ARC 的最小尺寸。默认是 vfs.zfs.arc_meta_limit 的一半。调整此值以防止其他应用程序压榨出整个 ARC。在运行时用 sysctl(8)/boot/loader.conf/etc/sysctl.conf 来调整这个值。

  • vfs.zfs.vdev.cache.size - 预先分配的内存量,作为池中每个设备的缓存。使用的总内存量将是这个值乘以设备的数量。在启动时和 /boot/loader.conf 中设置此值。

  • vfs.zfs.min_auto_ashift - 在创建池时自动使用的较低 ashift(扇区大小)。该值是二的幂。默认值 9 代表 2^9=512,即扇区大小为 512 字节。为了避免写入放大并获得最佳性能,将此值设置为池中设备使用的最大扇区大小。 普通驱动器有 4KB 的扇区。 在这些驱动器上使用默认的 9 作为 ashift 会导致这些设备的写入放大。单个 4KB 的写入所包含的数据被写成 8 个 512 字节的写入。在创建池时,ZFS 试图从所有设备中读取本地扇区大小,但具有 4 KB 扇区的驱动器报告说它们的扇区是 512 字节,以实现兼容。在创建池之前,将 vfs.zfs.min_auto_ashift 设置为 122^12=4096),迫使 ZFS 在这些驱动器上使用 4KB 块以获得最佳性能。 强制 4KB 区块对于有计划的磁盘升级的池也很有用。未来的磁盘使用 4KB 扇区,而且在创建池后,ashift 值不能改变。 在一些特定的情况下,较小的 512 字节的块大小可能是更好的。当使用 512 字节的磁盘用于数据库或作为虚拟机的存储时,在小的随机读取过程中传输的数据较少。这可以在使用较小的 ZFS 记录大小时提供更好的性能。

  • vfs.zfs.prefetch_disable - 禁用预取。值为 0 时启用,1 时停用。默认值是 0,除非系统的内存小于 4GB。预取的作用是将比请求的更大的块读入 ARC,希望很快就能需要这些数据。如果工作负载有大量的随机读取,禁用预取实际上可能会通过减少不必要的读取来提高性能。在任何时候都可以用 sysctl(8) 调整这个值。

  • vfs.zfs.vdev.trim_on_init - 控制添加到池中的新设备是否对其运行 TRIM 命令。这可以确保 SSD 的最佳性能和寿命,但需要额外的时间。如果设备已经被安全擦除,禁用此设置将使新设备的添加更快。在任何时候用 sysctl(8) 调整这个值。

  • vfs.zfs.vdev.max_pending - 限制每个设备的未决 I/O 请求的数量。一个较高的值会使设备的命令队列保持满员,并可能带来更高的吞吐量。一个较低的值将减少延迟。在任何时候都可以用 sysctl(8) 调整这个值。

  • vfs.zfs.top_maxinflight - 每个顶层 vdev 的未完成 I/O 的最高数量。限制命令队列的深度以防止高延迟。这个限制是每个顶级vdev的,意味着这个限制独立地适用于每个 镜像RAID-Z 或其他 vdev。在任何时候都可以用 sysctl(8) 调整这个值。

  • vfs.zfs.l2arc_write_max - 限制每秒钟写入 L2ARC 的数据量。这个调节器通过限制写入设备的数据量来延长 SSD 的寿命。在任何时候都可以用 sysctl(8) 调整这个值。

  • vfs.zfs.l2arc_write_boost - 在 vfs.zfs.l2arc_write_max 的基础上增加这个可调控的值,并增加对 SSD 的写入速度,直到驱逐 L2ARC 的第一个块。这个 “Turbo Warmup Phase” 可以减少重启后空的 L2ARC 带来的性能损失。在任何时候都可以用 sysctl(8) 调整这个值。

  • vfs.zfs.scrub_delay - 在 scrub 过程中,每个 I/O 之间延迟的刻度数。为了确保 scrub 不干扰池的正常运行,如果有任何其他 I/O 正在发生, scrub 将在每个命令之间延迟。这个值控制 scrub 所产生的总 IOPS(每秒 I/O 数)的限制。设置的颗粒度由 kern.hz 的值决定,默认为每秒 1000 次。改变这个设置会导致不同的有效 IOPS 限制。默认值是 4,导致的限制是: 1000 ticks/sec / 4 = 250 IOPS。使用一个 20 的值会得到一个限制: 1000 ticks/sec / 20 = 50 IOPS。池子上的最近活动限制 scrub 的速度,这由 vfs.zfs.scan_idle 决定。在任何时候都可以用 sysctl(8) 调整这个值。

  • vfs.zfs.resilver_delay - 在 resilver 过程中每次 I/O 之间插入延迟的毫秒数量。为了确保 resilver 不会干扰池的正常运行,如果有任何其他 I/O 正在发生,resilver 将在每个命令之间延迟。这个值控制 resilver 产生的总 IOPS(每秒 I/O 数)的限制。ZFS 通过 kern.hz 的值来决定设置的粒度,其默认值为每秒 1000 次。改变这个设置会导致不同的有效 IOPS 限制。默认值是 2,导致的限制是: 1000 ticks/sec / 2 = 500 IOPS。如果另一个设备失败可能导致池 Fault ,导致数据丢失,那么将池返回到 Online 状态可能更为重要。一个 0 值将给予 resilver 操作与其他操作相同的优先级,加速愈合过程。池上的其他最近活动限制 resilver 的速度,由 vfs.zfs.scan_idle 决定。在任何时候都可以用 sysctl(8) 调整这个值。

  • vfs.zfs.scan_idle - 在考虑池子是空闲的之前,从最后一次操作开始的毫秒数量。当池子处于空闲状态时,ZFS 会禁用 scrubresilver 的速率限制。在任何时候都可以用 sysctl(8) 调整这个值。

  • vfs.zfs.txg.timeout - 事务组 之间的最高秒数。当前的事务组将写入池中,如果从上一个事务组开始已经过这个时间,就会启动一个新的事务组。如果写入足够的数据,事务组可能会提前触发。默认值是 5 秒。一个更大的值可能会通过延迟异步写入来提高读取性能,但这可能会导致写入事务组时的性能不均衡。在任何时候都可以用 sysctl(8) 调整这个值。

20.6.2. i386 上的 ZFS

ZFS 提供的一些功能是内存密集型的,可能需要在内存有限的系统上进行调整以提高效率。

20.6.2.1. 内存

作为一个较低的值,总的系统内存应该至少是一千兆字节。推荐的 RAM 数量取决于池的大小和 ZFS 使用的功能。一般的经验法则是每 1TB 的存储量有 1GB 的 RAM。如果使用重复数据删除功能,一般的经验法则是每 TB 存储使用 5 GB RAM 进行重复数据删除。虽然有些用户使用的 ZFS 内存更少,但负载过重的系统可能会因为内存耗尽而恐慌。ZFS 可能需要对低于推荐内存要求的系统进行进一步的调整。

20.6.2.2. 内核配置

由于 i386™ 平台的地址空间限制,i386™ 架构上的 ZFS 用户必须在自定义的内核配置文件中加入这个选项,重新编译内核,然后重新启动。

  1. options KVA_PAGES=512

这就扩展内核地址空间,允许 vm.kvm_size 可调性超过 1GB 的强制限制,或者 PAE 的 2GB 限制。为了找到这个选项的最合适的值,将所需的地址空间(以兆字节为单位)除以 4。在这个例子中,512 代表 2GB。

20.6.2.3. 引导器的可调节选项

在所有的 FreeBSD 架构上增加 kmem 地址空间。在 /boot/loader.conf 中加入这些选项,然后重新启动,一个拥有 1GB 物理内存的测试系统就会受益。

  1. vm.kmem_size="330M"
  2. vm.kmem_size_max="330M"
  3. vfs.zfs.arc_max="40M"
  4. vfs.zfs.vdev.cache.size="5M"

关于 ZFS 相关调整的更详细的建议列表,请参见 https://wiki.freebsd.org/ZFSTuningGuide