如何处理多用户系统上的内存不足问题?

如何处理多用户系统上的内存不足问题?

当进程尝试分配比可用内存更多的内存时,通常很难以良好的方式处理这种情况。在某些情况下,程序可能能够释放非必要内存(例如缓存),但大多数情况下,这会导致致命异常(另请参阅[1]), 到交换和严重的系统减速或者甚至使用OOM 杀手

在单用户系统上,所有选项都是不好的,但至少你只能伤害自己(毕竟你要对在你的机器上运行的所有代码负责)。

然而,在多用户系统中,我期望 OOM 终止程序可以终止可能由其他用户拥有的某些进程。但存在某些限制,因为 OOM 终止程序会尝试查找“占用大量内存但寿命不长的进程”(请参阅这里)。

然而,想象一下这样一种情况:一个进程需要 x MB 的内存,并且存活时间不长(CPU 时间低),并且由用户 X 所有,而 x 的内存远远多于系统中的可用内存,用户 Y 可能会分配比可用内存更多的内存,并导致系统终止 X 的进程(因为它使用了更多的内存)。

这种情况听起来比单用户机器上的类似影响更可怕。可以设置每个用户的内存限制,甚至可以使用容器进一步分离进程。但据我所知,仅设置限制total_memory / number_of_users即可解决问题。但是,设置这样的限制会失去多用户系统的所有好处。这台机器实际上类似于一台机器中的多台单用户机器。人们通常希望允许一个用户在高峰时间使用更多内存,因为大多数时候用户所需的内存都比平均水平要少。

我最感兴趣的是在需要大量数据进行大量计算的情况下解决此问题。我猜想在 Web 服务器的情况下,人们可能能够更好地估计需要多少内存,因为有许多小操作而不是少数大操作。但即使在这种情况下,我也听说在正常情况下只应填充 50% 的内存,以避免在高峰期出现内存不足问题。这不是浪费 50% 的内存吗?

具体来说,我正在考虑托管 Jupyter 中心或类似的东西。但我不希望用户互相终止进程。

还有其他解决方案可以缓解这个问题吗?像 Travis CI 这样的大型云提供商如何处理此类问题?

答案1

我认为,如今限制一项任务对其他任务的影响的推荐方法是使用 cgroup 来限制其可以使用的内存。我发现最简单的方法是使用systemd-run。例如,这ls从 1000 字节的极低内存限制开始:

sudo systemd-run --uid $USER --gid $UID -p MemoryMax=1000 ls

运行 journalctl -f,你会看到该进程已被立即终止:

Memory cgroup out of memory: Kill process 3543 ((ls)) score 2503000 or sacrifice child
Killed process 3543 ((ls)) total-vm:205348kB, anon-rss:5612kB, file-rss:4276kB, shmem-rss:0kB

那么,您当然会想要超额配置机器,也许会给每个任务 70% 的可用内存?这将允许内存消耗达到峰值,同时仍能快速终止使用不合理内存量的进程。

答案2

禁用 oom killer(vm.oom-kill = 0在 读取的文件中sysctl)并禁用内存过量使用(vm.overcommit_memory = 2)。任何试图分配超过可用内存的进程都将被终止。其他进程不会被终止。所有内存都可以使用;不会浪费任何内存。

这并不能防止内存占用过大。内存 cgroup 有一个memory.soft_limit_in_bytes设置,看起来可能有用(与memory.limit_in_bytes和结合使用memory.memsw.limit_in_bytes),但我没有找到关于其如何运作的详细解释。

编辑:我查看了memory.soft_limit_in_bytes内核源代码中的用法。如果无法回收内存,则不会发生任何事情。

答案3

您可以设置 sysctl vm.oom_kill_allocating_task。设置此项后,如果某个进程的内存请求会导致内存耗尽,Linux 将终止该进程。

来自文档:

这将启用或禁用在内存不足的情况下终止触发 OOM 的任务。

如果将其设置为零,OOM 终止程序将扫描整个任务列表并根据启发式方法选择一个任务进行终止。这通常会选择一个占用大量内存的恶意任务,该任务在终止时会释放大量内存。

如果将其设置为非零,OOM 终止程序将直接终止触发内存不足情况的任务。这样可以避免昂贵的任务列表扫描。

如果选择了 panic_on_oom,它优先于 oom_kill_allocating_task 中使用的任何值。

默认值为 0。

相关内容