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

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

这是在SLES11 SP4上实现的testing。 该服务器有大量的内存,这使得它可以创build4GB的脏页面。

> 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 

这是我迄今为止的调查:

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

这是我的问题:

  • 在testing结束时有4GB的脏内存,我得出结论:IO调度器在上面的testing中没有被调用。 是对的吗?
  • 因为第一个dd完成之后缓慢仍然存在,所以我得出这样的结论:当dd填充缓冲区时(dd总是从同一buf写入),内核分配内存或任何“写入时复制”都不会发生。
  • 有什么方法可以深入调查被阻塞的东西吗? 任何有趣的计数器观看? 任何想法的争议来源?
  • 我们正在考虑减lessdirty_ratio值,在同步模式下执行第一个dd。 任何其他方向调查? 把第一个dd同步是否有缺点? 恐怕这将优先于其他“legits”进程进行asynchronous写入。

也可以看看

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

限制linux后台刷新(脏页)

https://stackoverflow.com/questions/375576​​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文件系统经验相距甚远。


EDIT2:

在@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 

DD是打开文件的参数:

 open("zer", O_WRONLY|O_CREAT|O_TRUNC|O_SYNC, 0666) = 3 

更改与notrunc选项,现在是

 open("zer", O_WRONLY|O_CREAT|O_SYNC, 0666) = 3 

同步写入即刻完成!

那么它是不是完全满足我的用例(我正在做一个msync 这种方式 ,但我现在能够跟踪什么写和msync做的不同!


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

实际上在SLES11下dd是打开文件的

 open("zer", O_WRONLY|O_CREAT|O_DSYNC, 0666) = 3 

和O_DSYNC == O_SYNC!

结论:

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

 dd if=/dev/zero of=zer oflag=dsync bs=512 count=1 conv=notrunc 

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

我有兴趣知道结果的一些事情。

  1. 最初用fallocate创build大文件然后写入它。

  2. 设置dirty_background_bytes要低得多(比如1GiB),并使用CFQ作为调度器。 请注意,在这个testing中,在大运行过程中运行小的代码可能会更好。

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

对于选项2,您可以使用ionice更多一点。 截止date明显比CFQ更快,尽pipeCFQ尝试组织每个进程的IO,使得您发现它可以让您通过每个进程更好地分享IO。

我读某处(现在不能find一个源代码),dirty_background_ratio将阻止对个人提交过程的写入(有效地使大进程变慢),以防止一个进程饿死所有其他进程。 鉴于现在我可以find的关于这种行为的信息很less,我不那么有信心,这将起作用。

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

我回答我自己的问题,但如果有人可以提出更好的build议,我会非常感激:)

在testing结束时有4GB的脏内存,我得出结论:IO调度器在上面的testing中没有被调用。 是对的吗?

这是完全错误的。 肮脏的记忆量不是一个好的指标。 这可以通过运行iostat轻松certificate,并且在dd oflag = sync正在运行时检查是否发生了大量的写入。

有什么方法可以深入调查被阻塞的东西吗? 任何有趣的计数器观看?

 perf record -e 'jbd:*' -e 'block:*' -ag 

对于较新的内核,用jbd2replacejbd。

任何想法的争议来源?

事实上,对于数据=有序的ext3,日记线程负责刷新磁盘上的数据。 刷新按照写入的顺序进行。 安装文件系统时,使用提交选项可以控制刷新的频率。

一个有趣的实验:使用commit = 60来挂载文件系统并禁用写回线程。 在运行第一个dd时,它在2s内完成,iostat显示没有IO被生成!

当使用oflag = sync运行第二个dd时,第一个dd生成的所有IO将被刷新到磁盘。

我们正在考虑减lessdirty_ratio值,在同步模式下执行第一个dd。

为了logging这两个解决scheme给出了很好的结 另一个好主意是将这些大文件放在一个单独的文件系统上(可能挂载的是data = writeback)

这不是特别链接到SLES11或更旧的内核。 在我尝试过的所有内核上都经历了同样的行为。

这是ext3预期的行为:在此文件系统上,同步写入块,直到所有先前的脏块都写入磁盘。 这就是开发者在过去几年完全跳过任何同步写入的确切原因。

Ext4,XFS,ZFS和BTRFS在这方面都比较好。 考虑到ext4是一个或多或less的替代ext3,你应该真的升级你的文件系统。