限制 Linux 后台刷新(脏页)

限制 Linux 后台刷新(脏页)

Linux 上的后台刷新发生在以下情况:有太多写入数据处于待处理状态(可通过 /proc/sys/vm/dirty_background_ratio 进行调整)或达到待处理写入的超时时间(/proc/sys/vm/dirty_expire_centisecs)。除非达到另一个限制(/proc/sys/vm/dirty_ratio),否则可能会缓存更多写入数据。进一步的写入将被阻止。

理论上,这应该会创建一个后台进程,在不干扰其他进程的情况下写出脏页。实际上,它确实会干扰任何执行非缓存读取或同步写入的进程。情况很糟糕。这是因为后台刷新实际上以 100% 的设备速度写入,此时任何其他设备请求都将被延迟(因为路径上的所有队列和写入缓存都已填满)。

有没有办法限制刷新过程每秒执行的请求数量,或者以其他方式有效地优先考虑其他设备 I/O?

答案1

经过大量使用 sysbench 进行基准测试后,我得出以下结论:

为了在性能方面生存下来

  • 恶意复制过程淹没脏页
  • 并且存在硬件写缓存(也可能没有)
  • 每秒同步读取或写入 (IOPS) 至关重要

只需转储所有电梯、队列和脏页缓存。脏页的正确位置是该硬件写缓存的 RAM 中。

将 dirty_ratio(或新的 dirty_bytes)调整到尽可能低的水平,但要注意连续吞吐量。在我的特定情况下,15 MB 是最佳值(echo 15000000 > dirty_bytes)。

这更像是一种黑客行为,而不是解决方案,因为 GB 的 RAM 现在仅用于读取缓存,而不是脏缓存。为了在这种情况下很好地运行脏缓存,Linux 内核后台刷新程序需要平均底层设备接受请求的速度,并相应地调整后台刷新。这并不容易。


比较的规格和基准:

dd在将零存入磁盘时进行测试,sysbench 显示巨大的成功,将 10 个线程的 16 kB fsync 写入从 33 提升到 700 IOPS(空闲限制:1500 IOPS),将单线程从 8 提升到 400 IOPS。

没有负载时,IOPS 不受影响 (~1500) 并且吞吐量略有降低 (从 251 MB/s 到 216 MB/s)。

dd称呼:

dd if=/dev/zero of=dumpfile bs=1024 count=20485672

对于 sysbench,test_file.0 准备为非稀疏文件:

dd if=/dev/zero of=test_file.0 bs=1024 count=10485672

sysbench 调用 10 个线程:

sysbench --test=fileio --file-num=1 --num-threads=10 --file-total-size=10G --file-fsync-all=on --file-test-mode=rndwr --max-time=30 --file-block-size=16384 --max-requests=0 run

sysbench 调用一个线程:

sysbench --test=fileio --file-num=1 --num-threads=1 --file-total-size=10G --file-fsync-all=on --file-test-mode=rndwr --max-time=30 --file-block-size=16384 --max-requests=0 run

更小的区块尺寸显示出更加剧烈的数字。

--file-block-size=4096,其中 dirty_bytes 为 1 GB:

sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
1 files, 10Gb each
10Gb total file size
Block size 4Kb
Number of random requests for random IO: 0
Read/Write ratio for combined random IO test: 1.50
Calling fsync() after each write operation.
Using synchronous I/O mode
Doing random write test
Threads started!
Time limit exceeded, exiting...
Done.

Operations performed:  0 Read, 30 Write, 30 Other = 60 Total
Read 0b  Written 120Kb  Total transferred 120Kb  (3.939Kb/sec)
      0.98 Requests/sec executed

Test execution summary:
      total time:                          30.4642s
      total number of events:              30
      total time taken by event execution: 30.4639
      per-request statistics:
           min:                                 94.36ms
           avg:                               1015.46ms
           max:                               1591.95ms
           approx.  95 percentile:            1591.30ms

Threads fairness:
      events (avg/stddev):           30.0000/0.00
      execution time (avg/stddev):   30.4639/0.00

--file-block-size=4096,其中 dirty_bytes 为 15 MB:

sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
1 files, 10Gb each
10Gb total file size
Block size 4Kb
Number of random requests for random IO: 0
Read/Write ratio for combined random IO test: 1.50
Calling fsync() after each write operation.
Using synchronous I/O mode
Doing random write test
Threads started!
Time limit exceeded, exiting...
Done.

Operations performed:  0 Read, 13524 Write, 13524 Other = 27048 Total
Read 0b  Written 52.828Mb  Total transferred 52.828Mb  (1.7608Mb/sec)
    450.75 Requests/sec executed

Test execution summary:
      total time:                          30.0032s
      total number of events:              13524
      total time taken by event execution: 29.9921
      per-request statistics:
           min:                                  0.10ms
           avg:                                  2.22ms
           max:                                145.75ms
           approx.  95 percentile:              12.35ms

Threads fairness:
      events (avg/stddev):           13524.0000/0.00
      execution time (avg/stddev):   29.9921/0.00

--file-block-size=4096,空闲系统上有 15 MB dirty_bytes:

sysbench 0.4.12:多线程系统评估基准

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
1 files, 10Gb each
10Gb total file size
Block size 4Kb
Number of random requests for random IO: 0
Read/Write ratio for combined random IO test: 1.50
Calling fsync() after each write operation.
Using synchronous I/O mode
Doing random write test
Threads started!
Time limit exceeded, exiting...
Done.

Operations performed:  0 Read, 43801 Write, 43801 Other = 87602 Total
Read 0b  Written 171.1Mb  Total transferred 171.1Mb  (5.7032Mb/sec)
 1460.02 Requests/sec executed

Test execution summary:
      total time:                          30.0004s
      total number of events:              43801
      total time taken by event execution: 29.9662
      per-request statistics:
           min:                                  0.10ms
           avg:                                  0.68ms
           max:                                275.50ms
           approx.  95 percentile:               3.28ms

Threads fairness:
      events (avg/stddev):           43801.0000/0.00
      execution time (avg/stddev):   29.9662/0.00

测试系统:

  • Adaptec 5405Z(具有保护功能的 512 MB 写缓存)
  • 英特尔至强 L5520
  • 6 GiB RAM @ 1066 MHz
  • 主板 Supermicro X8DTN(5520 芯片组)
  • 12 个 Seagate Barracuda 1 TB 磁盘
    • Linux 软件 RAID 10 中的 10
  • 内核 2.6.32
  • 文件系统 xfs
  • Debian 不稳定

总之,我现在确信此配置在数据库流量空闲、高负载甚至满负载情况下都能表现良好,否则顺序流量将无法满足这些需求。顺序吞吐量高于两个千兆位链路所能提供的吞吐量,因此稍微降低一点也没问题。

答案2

尽管调整内核参数可以解决问题,但实际上您的性能问题可能是 Adaptec 5405Z 控制器上的错误导致的,该错误已在 2012 年 2 月 1 日的固件更新中修复。发行说明称“修复了固件在高 I/O 压力下可能挂起的问题”。也许像您那样分散 I/O 就足以防止触发此错误,但这只是猜测。

以下是发行说明:http://download.adaptec.com/pdfs/readme/relnotes_arc_fw-b18937_asm-18837.pdf

即使您的具体情况并非如此,我认为这也可能对将来看到这篇文章的用户有所帮助。我们在 dmesg 输出中看到了一些类似下面的消息,这些消息最终引导我们进行固件更新:

aacraid: Host adapter abort request (0,0,0,0)
[above was repeated many times]
AAC: Host adapter BLINK LED 0x62
AAC0: adapter kernel panic'd 62.
sd 0:0:0:0: timing out command, waited 360s
sd 0:0:0:0: Unhandled error code
sd 0:0:0:0: SCSI error: return code = 0x06000000
Result: hostbyte=DID_OK driverbyte=DRIVER_TIMEOUT,SUGGEST_OK
sd 0:0:0:0: timing out command, waited 360s
sd 0:0:0:0: Unhandled error code
sd 0:0:0:0: SCSI error: return code = 0x06000028
Result: hostbyte=DID_OK driverbyte=DRIVER_TIMEOUT,SUGGEST_OK
sd 0:0:0:0: timing out command, waited 360s
sd 0:0:0:0: Unhandled error code
sd 0:0:0:0: SCSI error: return code = 0x06000028

以下是具有高 I/O 挂起修复的固件发行说明中列出的 Adaptec RAID 控制器的型号:2045、2405、2405Q、2805、5085、5405、5405Z、5445、5445Z、5805、5805Q、5805Z、5805ZQ、51245、51645、52445。

答案3

包含“WBT”的内核:

块层的改进, LWN.net

通过写回节流,[块层] 尝试使用从 CoDel 网络调度程序借用的策略,在不产生过多 I/O 延迟的情况下获得最大性能。CoDel 跟踪观察到的网络数据包的最小延迟,如果延迟超过阈值,它就会开始丢弃数据包。在 I/O 子系统中,丢弃写入是被反对的,但采用的策略类似,即内核监视读取和写入的最小延迟,如果延迟超过阈值,它就会开始减少正在进行的后台写回量。此行为是在 4.10 中添加的;Axboe 表示,已经看到了相当不错的效果。

WBT 不需要切换到新的 blk-mq 块层。也就是说,它不适用于 CFQ 或 BFQ I/O 调度程序。您可以将 WBT 与 deadline / mq-deadline / noop / none 调度程序一起使用。我相信它也适用于新的“kyber”I/O 调度程序。

除了缩放队列大小来控制延迟之外,WBT 代码限制后台写回请求的数量作为计算的队列限制的比例。

运行时配置在 中/sys/class/block/*/queue/wbt_lat_usec

要查找的构建配置选项是

/boot/config-4.20.8-200.fc29.x86_64:CONFIG_BLK_WBT=y
/boot/config-4.20.8-200.fc29.x86_64:# CONFIG_BLK_WBT_SQ is not set
/boot/config-4.20.8-200.fc29.x86_64:CONFIG_BLK_WBT_MQ=y

您的问题陈述已得到 WBT 作者 100% 的确认——做得好:-)。

[补丁集] 块:缓冲写回限制

自古以来,我们的后台缓冲写回就很糟糕。当我们进行后台缓冲写回时,它应该对前台活动影响不大。这就是后台活动的定义……但据我所知,重度缓冲写入器的表现并不像这样。例如,如果我做这样的事情:

$ dd if=/dev/zero of=foo bs=1M count=10k

在我的笔记本电脑上,然后尝试启动 chrome,它基本上不会在缓冲写回完成之前启动。或者,对于面向服务器的工作负载,安装大型 RPM(或类似产品)会对数据库读取或同步写入产生不利影响。当这种情况发生时,我会被人大喊大叫。

一些最近测试的结果可以在这里找到:

https://www.facebook.com/axboe/posts/10154074651342933

请参阅先前的帖子以获得关于补丁集的更详细描述。

答案4

/proc/meminfo 中 Dirty 的平均值是多少?通常,该值不应超过 /proc/sys/vm/dirty_ratio。在专用文件服务器上,我将 dirty_ratio 设置为非常高的内存百分比 (90),因为我永远不会超过它。您的 dirty_ration 太低,达到该值时,一切都会崩溃,请提高它。

相关内容