我最近检查了 RHEL7.2,它几乎完全挂起,只是因为它写入了 CIFS 文件系统。在默认设置dirty_ratio = 30
和 cifs 缓存(读取和写入)的情况下,这些脏页大部分是 cifs 页。
在内存压力下,当系统回收大部分读缓存时,系统顽固地尝试刷新并回收脏(写)缓存。因此,情况是巨大的 CPU iowait 伴随着出色的本地磁盘 I/O 完成时间、D 中的大量进程不间断等待以及完全无响应的系统。 OOM 杀手从未参与,因为有曾是系统未释放的可用内存。 (我认为 CIFS 也存在一个错误,它会使冲洗速度变得非常慢。但这里不要介意。)
我惊讶地发现内核处理将页面刷新到某些慢速远程 CIFS 设备的方式与超高速本地 SSD 驱动器完全相同。单独一个dirty_ratio
包是不明智的,它很快就会导致 30% 的 RAM 包含脏数据的情况最慢的设备。真是浪费钱。
这种情况是可以重现的;设置dirty_ratio = 1
完全解决问题。但为什么我使用cifs挂载就需要牺牲本地磁盘的缓存呢?
除了完全禁用某些设备的缓存或设置vm.dirty_ratio
为非常低的值之外,是否有任何方法可以将快速设备“列入白名单”以获得更多写入缓存?或者让慢速设备(或远程“设备”,如 //cifs/paths)使用较少的写入缓存?
RHEL 7.2 的内核版本称为 3.10.0-327。 (它基于 3.10.0,但包含数年的向后移植)。
答案1
每个设备的 dirty_ratio
问:有没有办法将快速设备“列入白名单”以获得更多写入缓存?或者让慢速设备(或远程“设备”,如 //cifs/paths)使用较少的写入缓存?
有一些设置可以实现这一点,但它们并不像您希望的那样有效。请参阅bdi
以下中的(“支持设备”)对象sysfs
:
linux-4.18/文档/ABI/测试/sysfs-class-bdi
最小比率(读写)
在正常情况下,每个设备都会获得总回写缓存的一部分,该部分与其当前相对于其他设备的平均写出速度相关。
“min_ratio”参数允许将回写缓存的最小百分比分配给特定设备。例如,这对于提供最低 QoS 很有用。
最大比率(读写)
允许限制特定设备使用不超过给定百分比的回写缓存。当我们想要避免一个设备占用全部或大部分回写缓存的情况下,这非常有用。例如,如果 NFS 挂载很容易卡住。
问题是“此设置仅在我们总共有超过 (dirty_background_ratio+dirty_ratio)/2 脏数据后才会生效。因为这是我们开始限制进程时的脏数据量。因此,如果您想要的设备limit 是当前写入的唯一一个,该限制不会产生太大影响。”进一步阅读:
- LKML 帖子,作者:Jan Kara(2013)。
- “测试用例”,位于本答案的末尾。
- 提交 5fce25a9df48在 v2.6.24 中。 “如果系统上有很多空间,我们允许违反 bdi 限制。一旦达到总限制的一半,我们就开始强制执行 bdi 限制......”这是添加内部每设备的同一内核版本的一部分“限制”。所以“限制”总是这样工作,除了预发行版 v2.6.24-rc1 和 -rc2 之外。
为简单起见,让我们忽略 30% 设置并假设默认值:dirty_background_ratio=10 和 dirty_ratio=20。在这种情况下,进程可以毫无延迟地脏页,直到系统整体达到 15% 的点。
问:这种情况是可以重现的;设置
dirty_ratio = 1
完全解决问题。
:-/
这听起来类似于 LWN.net 撰写的一篇文章中提到的“有害的 USB 记忆棒失速问题”。不幸的是这篇文章是误导性的。它非常困惑,以至于编造了一个与报告的问题不同的问题。
一种可能性是您正在重现更具体的缺陷。如果您可以将其报告给内核开发人员,他们也许能够分析它并找到解决方案。喜欢与人的互动透明大页曾是解决了。您应该使用上游内核重现该问题。或者与您的付费支持联系人联系:)。
否则,可以应用一个补丁来公开内部strictlimit
设置。这让你变成max_ratio
一个严格的限制。该补丁尚未应用于主线。如果有足够多的人表现出对此的需求,则可能会应用该补丁,或者可能会鼓励一些工作来消除对此的需求。
我担心的是,虽然该功能可能有用,但可能不会充分地有助于证明其包含的合理性。因此,我们最终将通过其他方式解决这些问题,然后我们将继续维护这个过时的遗留功能。
我认为除非有人能够证明这是好的、完整的并且足以解决“足够大”的问题集,否则我将通过该补丁[1]。人们怎么看?
[1] 事实上,我会把它放在 -mm 中并维护它,所以下次有人报告问题时我可以说“嘿,试试这个”。
mm-add-strictlimit-knob-v2.patch
依然坐在-mm里。有几次,人们提到了更好地自动调整脏缓存的想法。不过我还没有找到很多这方面的工作。一个有吸引力的建议是为每个设备保留 5 秒的回写缓存。然而,设备的速度可能会突然改变,例如取决于 IO 模式是随机的还是顺序的。
分析(但没有结论)
问:我惊讶地发现内核将刷新页面处理到某个慢速远程 CIFS 设备的方式与处理超快速本地 SSD 驱动器的方式完全相同。
这些处理方式并不完全相同。请参阅上面 BDI 文档的引用。 “每个设备都被分配了与其当前平均写出速度相关的总回写缓存的一部分。”
然而,如果慢速设备是唯一被写入的设备,那么这仍然使得慢速设备有可能将整个回写缓存填充到 15-20% 标记之间的某个位置。
如果您开始写入的设备的最大写回缓存的允许份额小于其允许的份额,则“脏限制”代码应该做出一些调整。这可以让您使用一些剩余的空间,并避免必须等待慢速设备为您腾出空间。
该文档建议添加 min_ratio 和 max_ratio 设置,以防您的设备速度发生不可预测的变化,包括在 NFS 服务器不可用时停止。
问题是,如果脏节流无法控制慢速设备,并且它会设法填满(或接近)20%的硬限制。
我们感兴趣的脏节流代码在 v3.2 中被重新调整。有关介绍,请参阅 LWN.net 文章“无 IO 脏节流”。此外,发布后,Fengguang Wu 在 LinuxCon Japan 上发表了讲话。他的演示幻灯片非常详细且内容丰富。
目标是将 BDI 的所有写回委托给专用线程,以允许更好的 IO 模式。但他们也必须改用不太直接的节流系统。充其量,这会使代码更难推理。它已经过充分测试,但我不确定它是否涵盖了所有可能的操作机制。
事实上查看 v4.18,有显式后备代码对于您的问题的更极端版本:当一个 BDI 是完全地无反应。它试图确保其他 BDI 仍然可以取得进展,但是......它们在可以使用多少写回缓存方面会受到更多限制。即使只有一名写入者,性能也可能会下降。
问:在内存压力下,当系统回收大部分读缓存时,系统顽固地尝试刷新并回收脏(写)缓存。因此,情况是巨大的 CPU iowait 伴随着出色的本地磁盘 I/O 完成时间、D 中的大量进程不间断等待以及完全无响应的系统。 OOM 杀手从未启动,因为系统没有释放可用内存。 (我认为 CIFS 也存在一个错误,它会使冲洗速度变得非常慢。但这里不要介意。)
您提到您的系统面临内存压力。这是一个非常具有挑战性的案例的一个例子。当“可用”内存下降时,可能会给回写缓存的大小带来压力。 “dirty_ratio”实际上是“可用”内存的百分比,这意味着可用内存+页面缓存。
这种情况在原作中就被注意到了。有一种尝试缓解它。它表示“新的脏限制不会避免限制轻脏器,但可能会将其睡眠时间限制为 200 毫秒。”
“max_ratio”的测试用例
设置虚拟机/笔记本电脑/其他任何东西,这可以不是拥有昂贵的大量 RAM。运行dd if=/dev/zero bs=1M of=~/test
并使用 观察写入缓存grep -E '^(Dirty:|Writeback:)' /proc/meminfo
。您应该看到脏+写回围绕“设定点”稳定下来。
设定点为 17.5%,介于 15% 和 20% 之间。我在 Linux v4.18 上的结果是这里。如果您想查看准确的百分比,请注意比率是不是总 RAM 的百分比;我建议您在 dirty_balance_pages() 中使用跟踪点。
max_ratio
我使用文件系统 BDI 中的不同值运行此测试。正如预期的那样,不可能将回写缓存限制在 15% 以下。
答案2
我认为你可以通过设置每个设备的脏率比例
echo RATIO > /sys/class/bdi/MAJOR:MINOR/max_ratio
答案3
经过试验,我发现dirty_ratio
“包”的平衡效果相当好。使页面变脏的进程受到某种限制。一个cp
进程可以轻松占用几乎所有可能的写入缓存,但即使您运行 10 个突发竞争进程,它们也很少达到写入缓存上限 (dirty_ratio)。
因此,我将所有问题归因于我提到的与 CIFS 相关的错误。如果更多进程想要写入快速本地磁盘,内核将减少 CIFS 的使用。在这里,更多进程只想使用内存,并且由于上述错误,内核无法刷新和回收大型 CIFS 写入缓存。如果不是 bug,那么 30% dirty_ratio 可能不会成为问题。