为什么在系统负载较重的情况下进程会被 I/O 阻塞?

为什么在系统负载较重的情况下进程会被 I/O 阻塞?

我有一个工作站(2 个 Intel Xeon 系列 CPU 和 128GiB RAM),运行多个虚拟机,虽然 CPU 综合使用率 <30%,但平均负载在 20 到 25 之间。例如,如果我执行命令tar -xzvf vm_data.tgz --directory vm4/ --strip-components=1,则该gzip进程 90% - 99% 的时间被 I/O 阻塞,并且该命令需要永远完成:

在此输入图像描述

另一方面,与 SATA 3.0 或 SSD 相比,对磁盘的实际读取和写入非常低(我使用的是单个金士顿 SA400S37960GSSD)硬件限制。

什么可能导致进程(gzip在我的示例中)在 I/O 之后等待,而实际磁盘读取和写入似乎非常低?我的第一个想法是,也许系统中断非常高,这就是阻塞 I/O 的原因,但据此看来情况/proc/interrupts并非如此,因为没有一个计数器快速增加。

答案1

从您的报告显示 ~40G 开始自由的内存(我知道这并不完全是可用的内存但是,让我们保留 40G 可用的快速和肮脏的演算。缓冲区/缓存占用了 12G,由于没有提供详细信息,我们将承认充满了......脏数据。

因为vm.dirty_ratio默认为20%,20%为40G = 8G < 12G...

我怀疑您的系统运行超出了命令进程自行写回的限制。换句话说,发行阻塞写道。

然后我会检查系统的实际限制是什么:

$ sysctl -a | grep dirty

如果您发现 vm.dirty_ratio 实际上是其默认值,请增加它。 (您可以轻松达到 80%,无需担心,如果我没记错的话,Oracle 一直推荐这个值。)

当你这样做时,你还可以降低它的同伴(vm.dirty_background_ratio),通常默认为10。低延迟系统建议尽可能低的值(1),我个人将其设置为3。这将使写回守护进程能够更快地操作,延迟缓存超过 dirty_ratio 固定限制的时间点。

您可以通过将值回显到目录结构的相应条目中来进行临时更改/proc/sys/vm/。为了使这些更改永久生效(重新启动后),您可以编辑/etc/sysctl.conf

这是进程阻塞的直接原因,然后是写入设备看起来如此缓慢以至于填充缓存超过 dirty_ratio 限制的原因:请参阅 artem-s-tashkinov 答案。

答案2

许多年前,我的生产 MySQL 数据库遇到了非常类似的问题。事实证明,它的文件非常碎片化,备份它们会导致所有其他磁盘操作永远无法完成。

请发布以下输出:

find vm4 -type f | while read filename; do sudo filefrag "$filename" | egrep -v ": 1 extent|: 0 extents"; done | sort

为了解决这个问题,如果我的猜测是正确的,您需要对虚拟机文件进行碎片整理。

答案3

从 Centos7 (3.10.0.1062) 切换到 ElRepo kernel-ml (5.11.6) 后我注意到这一点:写回速度提高了大约 10 倍(从 2 Mb/秒到 20Mb/秒),但我使用的是 Samsung NVMe 400G 驱动器能够超过 2000 Mb/秒,所以我期望更好。然后我将 ext4 挂载切换为“nodelalloc,dioread_nolock”,现在我的写回速度超过 1500Mb/秒。由于我有 512GB 内存,并且 dirty_background_ratio = 10、dirty_ratio = 20,在解压包含许多中型(30-50kb)文件的大文件夹时,脏页增长到超过 50 GB(速度约为 500Mb/秒,受限于我的源 HDD RAID 速度),然后突然写回以 1500+Mb/秒的速度发生,持续约 35 秒以上。在 35 秒以上的写回期间,tar 作业降至 0% CPU 和 0% IO。关于写回内核线程的某些事情必须需要一个锁,而 tar write 系统调用也需要这个锁,而这种行为在 Centos7 (3.10.0.1062) 中绝对不存在。

所以OP描述的行为是真实的,但似乎是最近才引入的。

相关内容