生成大量脏页会阻塞同步写入

fre*_*dge 5 linux performance filesystems memory sles11

我们有进程在后台写入大文件。我们希望这些对其他流程的影响最小。

这是在 SLES11 SP4 上实现的测试。服务器拥有大量内存,可以创建 4GB 的脏页。

> dd if=/dev/zero of=todel bs=1048576 count=4096
4096+0 records in
4096+0 records out
4294967296 bytes (4.3 GB) copied, 3.72657 s, 1.2 GB/s
> dd if=/dev/zero of=zer oflag=sync bs=512 count=1  
1+0 records in
1+0 records out
512 bytes (512 B) copied, 16.6997 s, 0.0 kB/s

real    0m16.701s
user    0m0.000s
sys     0m0.000s
> grep Dirty /proc/meminfo
Dirty:           4199704 kB
Run Code Online (Sandbox Code Playgroud)

这是我到目前为止的调查:

  • SLES11 SP4 (3.0.101-63)
  • 输入 ext3(rw、nosuid、nodev、noatime)
  • 截止日期调度程序
  • 当时超过 120GB 的可回收内存
  • dirty_ratio 设置为 40%,dirty_background_ratio 设置为 10%,30 秒到期,5 秒回写

以下是我的问题:

  • 在测试结束时有 4GB 的脏内存,我得出结论,IO 调度程序在上面的测试中没有被调用。那正确吗?
  • 由于第一个 dd 完成缓慢仍然存在,我得出的结论是,这个问题也与内核分配内存或 dd 填充缓冲区时发生的任何“写入时复制”无关(dd 总是从同一个 buf 写入)。
  • 有没有办法更深入地调查被阻止的内容?有什么有趣的柜台可以看吗?关于争论的来源有什么想法吗?
  • 我们正在考虑要么减少dirty_ratio 值,要么在同步模式下执行第一个dd。还有其他方向可以调查吗?将第一个 dd 同步是否有缺点?我担心它会优先于其他进行异步写入的“合法”进程。

也可以看看

https://www.novell.com/support/kb/doc.php?id=7010287

限制 linux 后台刷新(脏页)

/sf/ask/26290351/​​5/what-posix-fadvise-args-for-sequential-file-write/3756466?sgp=2#3756466

http://yarchive.net/comp/linux/dirty_limits.html


编辑:

同一设备下有一个ext2文件系统。在这个设备上,根本没有冻结!唯一的性能影响发生在刷新脏页期间,同步调用可能需要长达 0.3 秒,与我们使用 ext3 文件系统的体验相去甚远。


编辑2:

在@Matthew Ife 评论之后,我尝试在没有 O_TRUNC 的情况下进行同步写入打开文件,您不会相信结果!

> dd if=/dev/zero of=zer oflag=sync bs=512 count=1
> dd if=/dev/zero of=todel bs=1048576 count=4096
> dd if=/dev/zero of=zer oflag=sync bs=512 count=1 conv=notrunc
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.000185427 s, 2.8 MB/s
Run Code Online (Sandbox Code Playgroud)

dd 正在打开带有参数的文件:

open("zer", O_WRONLY|O_CREAT|O_TRUNC|O_SYNC, 0666) = 3
Run Code Online (Sandbox Code Playgroud)

使用 notrunc 选项更改,现在是

open("zer", O_WRONLY|O_CREAT|O_SYNC, 0666) = 3
Run Code Online (Sandbox Code Playgroud)

同步写入立即完成!

好吧,它对我的​​用例并不完全满意(我正在以这种方式进行 msync 。但是我现在能够跟踪 write 和 msync 的不同之处!


最后编辑:我不敢相信我打了这个:https : //www.novell.com/support/kb/doc.php?id=7016100

实际上在 SLES11 dd 下打开文件

open("zer", O_WRONLY|O_CREAT|O_DSYNC, 0666) = 3
Run Code Online (Sandbox Code Playgroud)

和 O_DSYNC == O_SYNC!

结论:

对于我的用例,我可能应该使用

dd if=/dev/zero of=zer oflag=dsync bs=512 count=1 conv=notrunc
Run Code Online (Sandbox Code Playgroud)

在 SLES11 下,无论 strace 说什么,运行 oflag=sync 都将真正运行 oflag=dsync。

Mat*_*Ife 3

有几件事我很想知道结果。

  1. 最初创建大文件,fallocate然后写入其中。

  2. 将 dirty_background_bytes 设置得低得多(比如 1GiB)并使用 CFQ 作为调度程序。请注意,在此测试中,在大型运行的中间运行小型可能是更好的表示。

因此,对于选项 1,您可能会发现您避免了所有语义data=ordered,因为块分配已经(并且很快)完成,因为它是通过预先分配的,fallocate并且元数据是在写入之前设置的。测试情况是否确实如此将会很有用。尽管它会提高性能,但我有一些信心。

对于选项 2,您可以多使用 ionice。尽管 CFQ 尝试组织每个进程的 IO,但 Deadline 显然比 CFQ 更快,因此您会发现它可以在每个进程中更好地共享 IO。

我在某处读到(现在找不到来源),dirty_background_ratio 将阻止针对单个提交进程的写入(有效地使大进程变慢),以防止一个进程使所有其他进程挨饿。鉴于我现在能找到的关于这种行为的信息很少,我不太相信这会起作用。

哦:我应该指出,这fallocate依赖于范围,您需要使用 ext4。