> For the complete documentation index, see [llms.txt](https://handbook.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://handbook.bsdcn.org/di-23-zhang-z-wen-jian-xi-tong-zfs/23.8.-gao-ji-zhu-ti.md).

# 23.8.高级主题

## 23.8.1. 调整

调整可调参数，使 ZFS 在不同的工作负载下表现最佳。FreeBSD 将 ZFS 内核可调参数作为 **sysctl(8)** 变量暴露在 `vfs.zfs` 下；**zfs(4)** 记录了每个可调参数及其默认值。需要在引导时生效的值设置在 **/boot/loader.conf** 中；运行时可调整的值用 **sysctl(8)** 调整，并在 **/etc/sysctl.conf** 中永久保存。

* `vfs.zfs.arc.max` - [ARC](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) 的上限大小。默认值 `0` 让 ZFS 根据物理内存大小自动调整 ARC 大小。如果系统运行其他可能需要内存的守护进程或进程，请使用较小的值；参见 [ARC 大小与监控](#id-23.8.2.-arc-da-xiao-yu-jian-kong) 一节。可在运行时用 **sysctl(8)** 调整此值，并在 **/boot/loader.conf** 或 **/etc/sysctl.conf** 中设置。
* `vfs.zfs.arc.min` - [ARC](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) 的下限大小。默认值 `0` 让 ZFS 自动选择一个较小的最小值。增大此值可防止其他应用程序挤出整个 ARC。可在运行时用 **sysctl(8)** 调整此值，并在 **/boot/loader.conf** 或 **/etc/sysctl.conf** 中设置。
* `vfs.zfs.arc.meta_balance` - [ARC](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) 中缓存元数据与文件数据之间的平衡；值大于 `100` 时越来越倾向于元数据，默认值为 `500`。如果工作负载涉及对大量文件和目录的操作，或频繁的元数据操作，增大此值可以提高性能，但代价是较少的文件数据能适应 ARC。此可调参数替代了 OpenZFS 2.2 中移除的 `vfs.zfs.arc.meta_limit`。可随时通过 **sysctl(8)** 调整此值。
* `vfs.zfs.vdev.min_auto_ashift` - 池创建时自动使用的最低 `ashift`（扇区大小）。该值是 2 的幂。默认值 `9` 表示 `2^9 = 512`，即 512 字节的扇区大小。为了避免 *写放大* 并获得最佳性能，应将此值设置为池中设备使用的最大扇区大小。有关 4 KB 扇区驱动器上的池为何应使用 `ashift` 值 12 的说明，请参见 [创建和销毁存储池](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.3.-zpool-guan-li.md)。
* `vfs.zfs.prefetch.disable` - 禁用预取。值为 `0` 时启用，值为 `1` 时禁用。默认值为 `0`。预取通过将比请求的块更大的数据块读取到 [ARC](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) 中，来期望稍后会需要这些数据。如果工作负载有大量随机读取，禁用预取可能会通过减少不必要的读取来提高性能。可随时通过 **sysctl(8)** 调整此值。
* `vfs.zfs.txg.timeout` - [事务组](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) 之间的最大秒数。当前事务组写入池中，如果自上一个事务组以来经过了此时间，则启动新的事务组。如果写入了足够的数据，事务组可能会提前触发。默认值为 5 秒。较大的值可能会通过延迟异步写入来提高读取性能，但这可能导致写入事务组时性能不均匀。可随时通过 **sysctl(8)** 调整此值。
* `vfs.zfs.l2arc.write_max` - 限制每秒写入 [L2ARC](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) 的数据量。此可调参数通过限制写入设备的数据量，延长 SSD 的使用寿命。可随时通过 **sysctl(8)** 调整此值。
* `vfs.zfs.l2arc.write_boost` - 将此可调参数的值添加到 `vfs.zfs.l2arc.write_max` 中，并在从 [L2ARC](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) 驱逐第一个块之前，提升 SSD 的写入速度。这个“加速预热阶段”减少了重启后空 L2ARC 带来的性能损失。可随时通过 **sysctl(8)** 调整此值。
* `vfs.zfs.l2arc.rebuild_enabled` - 让 [L2ARC](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) 的内容在重启后持久存在。默认值 `1` 让 ZFS 在导入池时根据缓存设备上存储的日志块重建 L2ARC，避免了空缓存原本需要的漫长预热期。将此值设置为 `0` 可始终从空的 L2ARC 开始。
* `vfs.zfs.vdev.max_active` - 池中每个设备上活跃 I/O 请求的上限数量。较高的值会保持设备命令队列满，从而可能提高吞吐量。较低的值则会减少延迟。可随时通过 **sysctl(8)** 调整此值。
* `vfs.zfs.vdev.*_min_active` 和 `vfs.zfs.vdev.*_max_active` - 调度器为每个 I/O 类别向每个设备发出的并发 I/O 请求的下限和上限数量：`sync_read`、`sync_write`、`async_read`、`async_write`、`scrub` 等。这些按类别的限制替代了旧版 ZFS 中基于延迟的 [scrub](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) 和 [重新同步](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) 节流。例如，增大 `vfs.zfs.vdev.scrub_max_active` 可让 scrub 使用每个设备队列的更大份额，更快完成，但代价是前台 I/O 延迟。
* `vfs.zfs.resilver_min_time_ms` - [重新同步](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) 在事务组刷新之间工作的最短时间（以毫秒为单位）；默认值为 `3000`（3 秒）。当降级池面临丢失另一块设备的风险时，增大此值可更快完成重新同步，但代价是减慢正常的池操作。可随时通过 **sysctl(8)** 调整此值。

## 23.8.2. ARC 大小与监控

ZFS 将最近和频繁使用的数据和元数据保存在 RAM 中的 [ARC](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) 中。ARC 按需增长直到 `vfs.zfs.arc.max`，并在其他程序需要内存时再次收缩，因此在专用存储服务器上，大部分 RAM 处于使用状态是正常的。ARC 以块在磁盘上的压缩形式存储它们，并在访问时解压。这种 *压缩 ARC* 让相同数量的 RAM 能缓存更多数据，提高了有效命中率。

**top(1)** 在其内存摘要行中显示当前 ARC 大小。`kstat.zfs.misc.arcstats` **sysctl(8)** 树暴露了详细的统计信息，包括当前大小、目标最大值以及命中和未命中计数器：

```sh
% sysctl kstat.zfs.misc.arcstats.size kstat.zfs.misc.arcstats.c_max kstat.zfs.misc.arcstats.hits kstat.zfs.misc.arcstats.misses
kstat.zfs.misc.arcstats.size: 8963041280
kstat.zfs.misc.arcstats.c_max: 15843122176
kstat.zfs.misc.arcstats.hits: 954912441
kstat.zfs.misc.arcstats.misses: 21356847
```

`filesystems/zfs-stats` Port 以人类可读的报告形式总结这些统计信息。

ARC 在内存压力下让出内存，但在 ZFS 与其他大型内存消费者（如数据库、虚拟机或 Jail）共享 RAM 的系统上，这种竞争可能导致双方性能不均匀。为 ARC 设置上限可为其他工作负载留下可预测的内存量。例如，要将 ARC 限制为 8 GB，将以下行添加到 **/boot/loader.conf**：

```ini
vfs.zfs.arc.max="8G"
```

用 **sysctl(8)** 更改 `vfs.zfs.arc.max` 会立即生效，不过收缩预热的 ARC 会逐步释放内存。

## 23.8.3. 同步写入、ZIL 与 SLOG

每个池都有一个 [ZIL](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md)。使用 **fsync(2)** 或 `O_SYNC` 标志请求同步语义的应用程序，在 ZFS 将相应的意图日志记录提交到稳定存储之前，不会收到确认。默认情况下，ZIL 位于池的常规 vdev 上，因此每个同步写入都会与正常的池 I/O 竞争。异步写入绕过 ZIL，并随下一个 [事务组](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) 一起写入。

专用的 [日志](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md) vdev（通常称为 *SLOG*，即独立日志）将 ZIL 移到快速设备上：

```sh
# zpool add mypool log mirror nda0 nda1
```

SLOG 仅对产生大量同步写入的工作负载（如 NFS 服务器和数据库）有帮助。对纯异步工作负载没有影响。

几 GB 的 SLOG 容量就足够了：ZIL 最多保存几秒钟的传入写入（大约一个事务组的量），之后 ZFS 会将数据写入池中的最终位置。选择具有断电保护和低持续写入延迟的 SSD，并对日志设备进行镜像。ZFS 仅在崩溃后才读取 ZIL，因此如果未镜像的 SLOG 丢失同时伴随系统崩溃，会丢失那些已确认但未提交到池的写入。

`sync` 数据集属性控制同步写入行为：

* `sync=standard`（默认值）将同步写入提交到 ZIL，异步写入随下一个事务组写入。
* `sync=always` 将每个写入都视为同步写入，以性能换取安全性，仅对那些本应请求同步写入却未这样做的应用程序有帮助。
* `sync=disabled` 将每个写入都视为异步写入。

> **警告：** 使用 `sync=disabled` 时，ZFS 会在同步写入到达稳定存储之前就确认它们。池本身保持一致，但在崩溃或断电后，应用程序和 NFS 客户端会静默丢失最多几秒钟它们认为已安全写入的数据。不要对数据库、NFS 导出或任何其他重要数据使用 `sync=disabled`。

`logbias` 属性调整 ZFS 使用日志的方式：`logbias=latency`（默认值）倾向使用 SLOG 以最小化提交延迟，而 `logbias=throughput` 将同步数据直接写入主池，将 SLOG 容量保留给对延迟敏感的数据集。详见 **zfsprops(7)**。

## 23.8.4. 直接 I/O

> **注意：** 直接 I/O 需要 OpenZFS 2.3 或更高版本，首次出现在 FreeBSD 15.0 中。

`direct` 数据集属性控制 ZFS 如何处理使用 `O_DIRECT` 标志发出的请求：

* `direct=standard`（默认值）遵循 `O_DIRECT`：正确对齐的读取和写入绕过 [ARC](/di-23-zhang-z-wen-jian-xi-tong-zfs/23.10.-zfs-te-xing-he-shu-yu.md)。
* `direct=always` 将每个正确对齐的读取或写入都视为直接请求。
* `direct=disabled` 静默忽略 `O_DIRECT`，并通过 ARC 处理每个请求。

直接 I/O 避免了 ARC 的内存复制和缓存开销。在由非常快的 NVMe 设备组成的池上，这种开销可能在 I/O 本身的成本中占主导地位，而维护自己缓存的应用程序（如数据库）会因为两次缓存相同数据而浪费 RAM。对于此类工作负载，直接 I/O 可以提高吞吐量并减少内存使用。

ZFS 仍然验证直接读取和写入的校验和，因此数据完整性保护不变。直接写入必须与数据集的 `recordsize` 对齐；ZFS 会静默地将请求中未对齐的部分重定向到 ARC。完整的对齐规则和限制详见 **zfsprops(7)**。

## 23.8.5. `recordsize` 与 `volblocksize`

`recordsize` 属性设置 ZFS 在数据集中存储文件所使用的最大块，默认为 128 KB。将块大小与工作负载的 I/O 模式匹配，可避免读取和写入超出应用程序请求的数据量。

对于执行小随机读取和写入的数据库，在创建数据库文件之前，将 `recordsize` 设置为数据库页面大小，通常为 8 KB 或 16 KB。对于存储大型媒体文件或备份流（顺序读取和写入）的数据集，`recordsize=1M` 可减少元数据开销并提高压缩率。卷使用 `volblocksize` 属性代替，默认为 16 KB，并且在创建卷后无法更改。

更改 `recordsize` 仅影响新写入的文件；现有文件保留其原始块大小。即使 `zfs rewrite` 也不会将新的 `recordsize` 应用于现有文件，因为影响逻辑块大小的属性更改对重写的块没有影响；需要重新复制文件才能用新值存储它们。
