当未设置内存限制时,使用 cgroups v2 接收内存压力事件

当未设置内存限制时,使用 cgroups v2 接收内存压力事件

使用 cgroups v1,可以监听有关内存压力的事件。根据文档, 需要

  • 创建一个新的eventfd
  • 开放memory.pressure_level阅读
  • 开放cgroup.event_control写作
  • 写入{eventfd} {pressure_level_fd} {level}(其中levellowmediumcriticalevent_control
  • 等待直到从 eventfd 读取返回 8 个字节

当对即将耗尽内存的程序执行此操作时,您将收到一长串low事件,然后是一些mediumcritical,最后 OOM 杀手将运行。如果你想说服自己这一点,我准备了一份Rust 的小例子,您可以使用 执行它cargo build --release --examples && sudo target/release/examples/cv1

对于 cgroups v2 (文档),类似的事件可以通过

  • 设置 inotify 手表memory.events.local
  • 完全读取和解析文件,在收到每个事件后比较数字

当在 cgroup 中设置内存限制时,这有效(即使没有 root,与 v1 不同),并且您通常会收到至少一些 inotify 事件,其中 或 会high增加max。 (再次强调,如果你想说服自己相信这一点,请systemd-run --same-dir --pty --user -p MemoryMax=1G cargo run --example cv2按照上述要点进行操作。)

但是,当没有设置内存限制,或者限制高于可用内存时,进程将被终止,而不会收到事件。查看memory.pressure显示强劲的增长,因此内核在调用 OOM 杀手之前肯定知道发生了某些事情。有没有办法让它告诉我们,像 cgroups v1 这样的良好行为会提前发出很多警告?

注意:我知道一些相关问题(1,2), 但:

  • 它们很旧,问题/答案只考虑 cgroups v1
  • 我希望在 oom Killer 激活之前被触发,这样“生成高 oom_score_adj 金丝雀进程”的黑客就不会出现了。

答案1

读完后文档更仔细一点,我找到了答案。总而言之,您可以通过写入some 50000 2000000\0fd /proc/pressure/memory,然后轮询 fd 的PRI事件来观察内存压力。

我没有将其标记为已接受,因为我对此不满意:

  • 基于 cgroups 的变体 (at $CGROUP_FS/$GROUP/memory.pressure) 仅适用于 root - 如果您使用全局变体 at /proc/pressure/,即使您的进程仍然有大量可用内存,您也可能会收到事件。
  • 非 root 用户的最小间隔是 2 秒 - 在没有交换的系统上,这意味着您可能会在第一个事件发生之前被 OOM 杀死。

相关内容