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 太低,达到该值时,一切都会崩溃,请提高它。