配置 vm.overcommit_memory 的效果

配置 vm.overcommit_memory 的效果

我的 VPS 网络服务器运行在 CentOS 5.4(Linux 内核 2.6.16.33-xenU)上,由于 oom-killer 的启动,有时会(比如每月一次,大约几周)变得无响应。对服务器的监控表明,它通常不会耗尽内存,只是偶尔才会耗尽。

我读过一些博客,它们指出这一页讨论了使用以下 sysctl 设置来配置内核以更好地管理过度提交:

vm.overcommit_memory = 2
vm.overcommit_ratio = 80

我对此的理解(可能是错误的,但我找不到规范的定义来澄清)是,这可以防止内核过度分配超过交换 + 80% 物理内存的内存。

不过,我也读过一些其他消息来源表明这些设置不是一个好主意 - 尽管这种方法的批评者似乎在说“不要做破坏系统的事情,而不是尝试这种临时解决办法”,因为他们假设因果关系总是已知的。

我的问题是,这种方法的优点和缺点是什么,在托管大约 10 个低流量站点的 Apache2 Web 服务器环境中?在我的特定情况下,Web 服务器有 512Mb RAM,1024Mb 交换空间。这似乎在绝大多数情况下都足够了。

答案1

设置overcommit_ratio为 80 可能不是正确的做法。将值设置为小于 100 的任何值都是几乎总是不正确。

原因是 Linux 应用程序分配的内存比实际需要的多。假设它们分配 8kb 来存储几个文本字符串。那么,那里就有几 KB 未使用。应用程序经常这样做,这就是过度使用的目的。

因此,基本上,如果过量使用 100,内核将不允许应用程序分配比您拥有的内存(交换 + RAM)更多的内存。将其设置为小于 100 意味着您永远不会使用所有内存。如果要设置此设置,则应将其设置为高于 100,因为前面提到的情况很常见。
但是,虽然将其设置为大于 100 几乎总是正确的答案,但在某些情况下将其设置为小于 100 是正确的。如上所述,这样做您将无法使用所有内存。但是内核仍然可以。因此,您可以有效地使用它为内核保留一些内存(例如页面缓存)。

现在,至于您遇到的 OOM killer 触发问题,手动设置过度提交不太可能解决此问题。默认设置(启发式确定)相当智能。

如果您想知道这是否真的是问题的原因,请查看/proc/meminfoOOM 终止程序的运行时间。如果您看到Committed_AS接近CommitLimit,但free仍显示可用内存,那么您可以手动调整您的场景的过度使用。将此值设置得太低会导致 OOM 终止程序在您仍有大量可用内存时开始终止应用程序。将其设置得太高可能会导致随机应用程序在尝试使用分配给它们的内存时死亡,但实际上不可用(当所有内存实际上都被用完时)。

答案2

@dunxd 提到的文档中的第 9.6 节“过量使用和 OOM”特别形象地说明了允许过量使用带来的危险。不过,这80对我来说也很有趣,所以我进行了一些测试。

我发现这会overcommit_ratio影响所有进程可用的总 RAM。根进程似乎与普通用户进程并无区别。

将比率设置为100或更低应提供经典语义,其中返回值malloc/sbrk可靠。将比率设置为低于100可能是为缓存等非进程活动保留更多 RAM 的一种方法。

因此,在我的计算机上,有 24 GiB 的 RAM,禁用交换,使用 9 GiB,top显示

Mem:  24683652k total,  9207532k used, 15476120k free,    19668k buffers
Swap:        0k total,        0k used,        0k free,   241804k cached

这里有一些overcommit_ratio设置以及我的 RAM 消费者程序可以抓取多少 RAM(触及每个页面) - 在每种情况下,程序一旦malloc失败就会干净地退出。

 50    ~680 MiB
 60   ~2900 MiB
 70   ~5200 MiB
100  ~12000 MiB

同时运行多个,即使其中一些以 root 用户身份运行,也不会改变它们消耗的总量。有趣的是,它无法消耗最后 3+ GiB 左右;它们free并没有低于此处显示的值太多:

Mem:  24683652k total, 20968212k used,  3715440k free,    20828k buffers

实验很混乱——在所有 RAM 都被使用的时候,任何使用 malloc 的东西都容易崩溃,因为许多程序员在 C 中检查 malloc 失败时很糟糕,一些流行的集合库完全忽略它,而 C++ 和其他各种语言甚至更糟糕。

我所见过的大多数虚拟 RAM 的早期实现都是为了处理一种非常特殊的情况,即一个大型进程(比如说 51% 以上的可用内存)需要fork()运行exec()某个支持程序,通常是一个小得多的程序。具有写时复制语义的操作系统将允许这样做fork(),但有一个条件,即如果分叉的进程实际上试图修改太多内存页面(每个页面都必须实例化为独立于初始大型进程的新页面),它最终将被终止。父进程只有在分配更多内存时才会有危险,并且可以处理内存耗尽的情况,在某些情况下只需等待其他进程死亡,然后继续即可。子进程通常只是通过用一个(通常较小的)程序替换自身,然后就exec()不受限制了。

Linux 的过度使用概念是一种极端方法,既允许fork()发生,也允许单个进程大量过度分配。 OOM-killer 导致的死亡是异步发生的,即使对于负责任地处理内存分配。我个人讨厌全系统一般来说,过度使用,特别是 oom-killer - 它培养了一种不顾一切的内存管理方法,这种方法会感染库,并通过它们感染使用它们的每个应用程序。

我建议将比率​​设置为 100,并且还设置一个交换分区,该分区通常只会被大型进程使用 - 这些进程通常只使用其自身被塞入交换分区的一小部分,从而保护绝大多数进程免受 OOM 杀手错误功能的影响。这应该可以保护您的 Web 服务器免于随机死亡,如果它被编写为malloc负责任地处理,甚至可以避免自我死亡(但不要指望后者)。

这意味着我将使用它/etc/sysctl.d/10-no-overcommit.conf

vm.overcommit_memory = 2
vm.overcommit_ratio = 100

相关内容