关于Page Cache和dirty_background_bytes的误解

psy*_*ca0 5 linux performance io performance-tuning linux-kernel

我已经研究了一段时间了,但事情并不符合我的期望,但我不知道是因为有什么不对,还是我的期望是错误的。

所以,我有一个内存超过 100GB 的系统,我将我的内存设置dirty_background_bytes为 9663676416(9GB)和dirty_bytes两倍(19327352832 或 18GB)

在我看来,这应该让我最多可以将 9GB 写入文件,但实际上它只是位于内存中,不需要访问磁盘。Mydirty_expire_centisecs是默认值3000(30 秒)。

所以当我运行时:

# dd if=/dev/zero of=/data/disk_test bs=1M count=2000
Run Code Online (Sandbox Code Playgroud)

并跑了:

# while sleep 5; do egrep 'Dirty|Writeback' /proc/meminfo | awk '{print $2;}' | xargs; done
Run Code Online (Sandbox Code Playgroud)

(以 kb 为单位打印脏字节,以 kb 为单位打印回写,在 5 秒快照时以 kb 为单位打印 WritebackTmp)

我本来希望看到它转储 2GB 到页面缓存中,在那里等待 30 秒,然后开始将数据写入磁盘(因为它从未超过 9GB 背景比率)

相反,我看到的是:

3716 0 0
4948 0 0
3536 0 0
1801912 18492 0
558664 31860 0
7244 0 0
8404 0 0
Run Code Online (Sandbox Code Playgroud)

一旦页面缓存跳转,它就已经在写数据,直到我们回到我们开始的地方。

我实际上正在做的工作基本上是想看看我的进程瓶颈是磁盘 IO 还是其他一些因素,但在中间我被这种行为弄糊涂了。我认为只要进程仍在缓冲区中运行,磁盘写入性能就不应该真正相关,因为它应该只是转储到内存中。

那么,我是否误解了这些功能应该工作的方式,还是发生了一些奇怪的事情?

sho*_*hok 1

dd这可能是命令在每次迭代时取消链接并创建新的 disk_test的副作用。

尝试首先使用单个dd if=/dev/zero of=/data/disk_test bs=1M count=2000命令创建目标文件,然后使用命令运行循环dd if=/dev/zero of=/data/disk_test bs=1M count=2000 conv=notrunc,nocreat

解释: notrunc有所作为,因为在过去添加了一些启发式方法来防止应用程序执行replace-via-rename和replace-via-truncate并随后崩溃以损坏其数据。这种启发式基本上强制刷新属于打开->写入->截断文件的数据。

安装手册页

auto_da_alloc|noauto_da_alloc

当 noauto_da_alloc 通过以下模式替换现有文件时,许多损坏的应用程序不使用 fsync()

fd = open("foo.new")/write(fd,..)/close(fd)/ 重命名("foo.new", "foo")

或者更糟

fd = 打开(“foo”,O_TRUNC)/写入(fd,..)/关闭(fd)。

如果启用了auto_da_alloc,ext4将检测replace-via-rename和replace-via-truncate模式,并强制分配任何延迟的分配块,以便在下一次日志提交时,在默认的data=ordered模式下,在提交 rename() 操作之前,新文件将被强制写入磁盘。这提供了与 ext3 大致相同级别的保证,并避免了在延迟分配块被强制写入磁盘之前系统崩溃时可能发生的“零长度”问题。

还可以查看XFS 常见问题解答