文章背景与核心概要
本文探讨了在高性能计算服务器上放弃使用 Linux 严格内存超售(Strict Memory Overcommit)模式的实践经验。随着现代计算工作负载对虚拟内存的请求量远超其实际消耗量,传统的严格超售模式反而对用户造成了不必要的限制。
通过结合宽松的超售模式与 systemd 的 user.slice 资源控制(MemoryMax=),管理员成功在保护系统关键服务的同时,实现了服务器资源的最大化利用。这一转变不仅适应了现代应用对虚拟内存高请求、低实用的特性,也让通用计算服务器的内存管理方式与 SLURM 集群环境保持了高度一致。
We're no longer using Linux's strict memory overcommit mode
Summary
在重负载计算服务器上使用 Linux 的严格内存超售模式多年后,管理员最终放弃了这一做法。由于现代计算工作负载请求的虚拟内存往往远超其实际消耗量,严格超售模式人为地限制了用户。现在,服务器改用宽松的超售模式,并结合 systemd 的 cgroup 限制(针对 user.slice 设置 MemoryMax=),在保护系统服务的同时允许实现最大的资源利用率。
After years of using Linux's strict memory overcommit mode on heavy-duty compute servers, the administration has abandoned the practice. Because modern compute workloads frequently request vastly more virtual memory than they actually consume, strict overcommit was artificially limiting users. The servers now use relaxed overcommit combined with
systemdcgroup limits (MemoryMax=onuser.slice) to protect system services while allowing maximum resource utilization.
Background and Previous Setup
我们维护着两类多用户 Linux 机器: * 通用登录服务器,用于正常的 Unix 日常操作。 * 计算服务器,专门用于繁重的计算任务。
多年前,我们在两类机器上都实施了 Linux 内核的严格内存超售模式。我们很快发现这种模式不太适合登录服务器,但我们仍然在计算服务器上保持启用,尽管它偶尔会导致各种问题(亦见此处,以及此处)。
在登录服务器上,我们最终通过对每个用户的总内存使用量设置 systemd 内存限制来缓解这个问题。然而,这种方法不适用于我们的计算服务器,因为如果某个用户在其他用户闲置时,应当被允许利用所有可用的 RAM。
We maintain two types of multi-user Linux machines: * General-purpose login servers for normal Unix usage. * Compute servers dedicated to heavy-duty computation.
Many years ago, we implemented the Linux kernel's strict memory overcommit mode on both types of machines. We quickly learned this was a poor fit for login servers, but we left it enabled on the compute servers, despite causing occasional problems (also here, and here).
On the login servers, we eventually mitigated this by setting
systemdmemory limits on each user's total memory usage. However, this approach wasn't viable for our compute servers, where a single user should be allowed to utilize all available RAM if it is otherwise idle.
The Shift in Workload Demands
如今,限制服务器上总用户内存消耗更稳健的方法是在 user.slice 上设置 systemd 内存限制。这种方法针对的是所有来源的实际 RAM 使用量,而不是应用程序要求内核保留的理论内存量。
在研究这种方法时,我审查了用户实际消耗的 RAM 与其承诺地址空间(committed address space)的对比情况,这揭示了随时间推移发生的显著转变:
- 历史情况: 计算程序实际使用了它们所请求的大部分(庞大)内存量。严格超售是有道理的,因为请求 32 GB RAM 的作业通常确实需要它。
- 当前情况: 在整个
user.slice中,承诺的地址空间远远超过了实际的 RAM 使用量(正如我的指标收集所示)。
我们甚至观察到一些极端的边缘案例:程序请求了服务器中的所有 RAM,尽管它们只使用了其中的一小部分。虽然确切原因仍然是个推测(可能由现代编程语言的转变驱动),但数据清楚地表明,承诺的地址空间是物理 RAM 的好几倍,这证明了严格超售正在人为地阻碍我们的用户。
Today, a more robust way to cap total user memory consumption on servers is setting systemd memory limits on
user.slice. This targets actual RAM usage from all sources rather than the theoretical amount of memory applications ask the kernel to reserve.When investigating this approach, I reviewed how much RAM users were actually consuming compared to their committed address space, revealing a significant shift over time:
- Historically: Compute programs actually utilized most of the (large) amounts of memory they requested. Strict overcommit made sense because a job asking for 32 GB of RAM generally needed it.
- Currently: The committed address space drastically outpaces actual RAM usage across
user.slice(as shown in my metrics collection).We've even observed extreme edge cases where programs request all of the RAM in the server despite using only a fraction of it. While the exact cause remains speculative (likely driven by shifts in modern programming languages), the data clearly showed committed address space exceeding physical RAM by several multiples, proving that strict overcommit was artificially bottlenecking our users.
The New Approach: Cgroup Limits over Strict Overcommit
鉴于这些发现,我们在计算服务器上禁用了严格内存超售。取而代之的是,我们对 user.slice 应用了 MemoryMax= 指令,专门为关键系统服务预留了几个 GB 的内存 cf。
虽然这并没有解决每一个边缘案例,但它代表了一个明确的净收益:用户正在成功运行超越了以前会触发严格超售并将其实例杀死的阈值的工作负载。
Why Cgroup Limits Make Sense
在现代 Linux 内核环境中,除了少数专门的用例之外,基于 cgroup 的限制通常优于严格的内存超售。此外,这使我们的通用计算服务器与我们的 SLURM 环境保持了一致,在 SLURM 环境中,守护进程已经对孤立的单个作业强制执行了 cgroup 内存限制。
Given these findings, we disabled strict memory overcommit on our compute servers. Instead, we applied a
MemoryMax=directive touser.slice, reserving a few gigabytes specifically for critical system services cf.While this hasn't resolved every edge case, it represents a clear net positive: users are successfully running workloads that surpass the thresholds where strict overcommit would have previously killed them.
Why Cgroup Limits Make Sense
In a modern Linux kernel environment, cgroup-based limits are generally superior to strict memory overcommit outside of specialized use cases. Furthermore, this brings our general-purpose compute servers into alignment with our SLURM environment, where SLURM daemons already enforce cgroup memory limits on isolated individual jobs.
附言:总体而言,超售虚拟内存是明智的。在整个编程技术栈中,为了用内存换取速度这一标准的权衡,我们普遍存在资源过度分配的现象。
PS: Overcommitting virtual memory is sensible in general. Throughout the programming stack, we pervasively over-allocate resources as a standard trade-off of memory for speed.