当占用过多内存时自动暂停/休眠进程

当占用过多内存时自动暂停/休眠进程

我在 8 核 PC 上运行一个小型 Debian 计算集群,内存为 16GB。我正在运行大约 1k 个任务的批次(每个批次的预计完成时间总计为一个月)。单个任务是单线程的(因此我可以在每台 PC 上并行运行多个任务),不消耗太多 IO(启动时加载几兆字节的数据,退出时转储几兆字节的数据;否则不与外界通信),其运行时间未知(从几分钟到大约一周),其内存消耗未知(从几兆字节到大约 8GB;使用量可能缓慢或快速增长)。我希望在一台 PC 上并行执行尽可能多的此类任务,但我想避免过多的交换。

所以我有了一个想法:我可以监视这些任务的内存使用情况并暂停(kill -SIGSTOP)或休眠(使用类似低温PID) 任务占用过多内存,无法稍后重新启动。我所说的内存使用量是指“活动虚拟页面”的数量,或实际已使用的已分配而非共享内存页面的数量(这些任务可能会分配内存但不使用它们)。

我开始寻找一些工具来做到这一点。我知道我可以ulimit在内存受限的 cgroup 中运行任务,但是——如果我理解正确的话——这些解决方案将终止进程而不是暂停它。我想避免终止它们,因为我需要稍后从头开始启动它们,这意味着浪费时间。此外,它们实际上无法测量活动虚拟页面的数量。

我可以使用真正的虚拟机,但在这种情况下,它们似乎有相当大的开销——拥有单独的内核、内存分配等会减少可用内存;我必须运行 8 个虚拟机。而且,据我所知,它们还会增加计算开销。

我设想,实现此类行为的工具会将某个函数连接到页面错误通知,该通知会在每次页面错误时决定是否应该暂停进程。但我也不知道有任何工具可以这样工作。

还有其他选择吗?

答案1

您指的是进程检查点。后续内核中有一些工作可以提供此功能(与 freezer cgroup 结合),但尚未准备就绪。

不幸的是,这实际上很难实现,因为某些共享资源在固定时间段内不可用后就会变得陈旧(首先想到了 TCP,尽管这也可能适用于使用挂钟的应用程序,或者可能适用于在进程离线期间改变状态的某些共享内存)。

至于当达到一定内存利用率时停止该进程,我能想到一种可以做到这一点的方法。

  • 您创建一个包含冷冻机和内存子系统的 cgroup。
  • 将您的任务放在 cgroup 内。
  • 附加一个进程cgroup.event_control并设置一个你不想超过的内存阈值(这在内核文档
  • 超过时间后,您将冻结 cgroup。内核最终会将这些页面移出进行交换(前提是您的 cgroup 有足够的页面)。

请注意,“冻结” cgroup 不会将页面逐出到媒体持久位置,但当经过足够的时间并且页面需要用于其他用途时,它会将页面换出。

即使这确实有效(如果有效的话,那也相当不靠谱),你也需要考虑这是否真的能解决你的问题。

  • 您怎么知道让一个使用大量内存的进程更快地完成其内存密集期并放弃内存不是更好的选择?
  • 如果您尝试通过循环调度进程来公平地唤醒进程 - 您可能会说您所做的工作比 CPU 调度程序为您所做的更糟糕。
  • 如果某些进程比其他进程更重要(并且应该被唤醒更长时间/更快地完成),那么最好为它们分配更多的 CPU 时间,而不是让其他进程完全冻结。
  • 虽然速度会很慢,但您可以添加大量交换(这样您就永远不会过度使用),然后大大降低调度程序的交互性,以尝试帮助您减少激进的页面驱逐。这是在 中完成的sched_min_granularity_ns

不幸的是,最好的解决方案是能够检查任务。遗憾的是,大多数实现还不够具体。

或者,您可以等待几年,直到内核中提供适当的检查点/恢复!

答案2

我猜这个问题有点超出我的理解范围,或者我误解了它,但是你是在寻找类似的东西

ps auxww 然后检查 VSZ 列。然后如果 VSZ 达到一定数量,您会在该进程上执行 SIG 吗?然后按照您喜欢的间隔运行命令?

来自 ps 手册页

vsz 进程的 VSZ 虚拟内存大小(以 KiB 为单位,单位为 1024 字节)。当前不包括设备映射;这可能会发生变化。(别名 vsize)。

相关内容