github编辑

OpenZFS 事务延迟

当后端存储无法容纳传入写入的速率时,OpenZFS 写操作会被延迟。此延迟过程称为 OpenZFS 写入节流。由于不同硬件和工作负载具有不同的性能特性,需针对具体硬件和工作负载进行写入节流的调优。

写入被分组为事务。事务被分组为事务组。当一个事务组同步到磁盘时,该组中的所有事务都被视为完成。当对某个事务应用延迟时,会延迟该事务被分配到事务组。

要检查某个存储池是否启用了写入节流,可监控计数器 kstat dmu_tx_delaydmu_tx_dirty_delay

如果已经存在一个等待中的写事务,则延迟相对于该事务完成等待的时间。因此,计算得到的延迟时间与并发执行事务的线程数量无关。

如果只有一个等待者,则延迟相对于事务开始的时间,而不是当前时间。这会为该事务计入“已服役时间”。例如,如果一个写事务需要先读取间接块,那么延迟会从事务开始时计入,也就是在读取间接块之前。

事务所需的最小时间计算如下:

min_time = zfs_delay_scale * (dirty - min) / (max - dirty)
min_time 随后被限制在 100 毫秒以内

延迟具有两个可通过可调参数进行调整的自由度:

  1. 开始延迟的脏数据百分比由 zfs_delay_min_dirty_percent 定义。该值通常应设置为大于或等于 zfs_vdev_async_write_active_max_dirty_percent,以便在全速写入无法跟上传入写入速率之后才发生延迟。

  2. 曲线的尺度由 zfs_delay_scale 定义。粗略而言,该变量决定曲线中点处的延迟量。

延迟
 10ms +-------------------------------------------------------------*+
      |                                                             *|
  9ms +                                                             *+
      |                                                             *|
  8ms +                                                             *+
      |                                                            * |
  7ms +                                                            * +
      |                                                            * |
  6ms +                                                            * +
      |                                                            * |
  5ms +                                                           *  +
      |                                                           *  |
  4ms +                                                           *  +
      |                                                           *  |
  3ms +                                                          *   +
      |                                                          *   |
  2ms +                                              (midpoint) *    +
      |                                                  |    **     |
  1ms +                                                  v ***       +
      |             zfs_delay_scale ---------->     ********         |
    0 +-------------------------------------*********----------------+
      0%                    <- zfs_dirty_data_max ->               100%

请注意,由于延迟被加到最近事务剩余的未完成时间上,因此延迟实际上是 IOPS 的倒数。在此,中点 500 微秒对应 2000 IOPS。曲线的形状被设计为:在曲线前四分之三的区间内,累积脏数据量的小幅变化只会导致延迟量的相对小幅变化。

当以对数尺度表示延迟量时,其效果更易理解:

请注意,只有当脏数据量接近其上限时,延迟才会开始迅速增加。经过正确调优的系统目标应当是将脏数据量保持在该区间之外:首先确保为 I/O 调度器设置合适的限制,使其在后端存储上达到最佳吞吐量;然后通过调整 zfs_delay_scale 的值来增加曲线的陡峭程度。

参考代码: dmu_tx.carrow-up-right

最后更新于