如何配置 Linux 内存不足终止程序
本文介绍了 Linux 内存不足 (OOM) 终止程序以及如何查明该程序终止特定进程的原因。文中还介绍了配置 OOM 终止程序的方法,以便更好地适应各种不同环境的需求。
关于 OOM 终止程序
在支持数据库的服务器或应用服务器发生故障时,通常需要争分夺秒地恢复关键服务并使其正常运行,特别是在重要的生产系统中。在对故障初步分类之后尝试确定根本原因时,应用或数据库突然停止工作的原因通常是个谜。在某些情况下,追溯问题的根本原因会发现这是由于系统内存不足所导致,因此通过终止重要进程来保持系统运行。
Linux 内核根据系统上运行的应用需求来分配内存。由于许多应用会预先分配其内存但通常不使用所分配的内存,因此将内核设计为能过量使用内存以提高内存利用率。通过这种过量使用模型,内核分配的内存量可以超过实际具有的物理内存量。如果某个进程要实际使用向其分配的内存,则内核将向该应用提供这些资源。当过多的应用开始使用所分配的内存时,过量使用模型有时会造成问题,内核必须终止多个进程才能保持正常运行。内核回收系统上内存时所用的机制称为内存不足终止程序或简称为 OOM 终止程序。
确定进程终止原因
如果某应用已由 OOM 终止程序终止,在对该问题进行故障排除时,有一些线索可帮助查明进程终止的方式及原因。在下例中,我们将通过查看 syslog
来确定是否能找到问题的原因。由于内存不足情况,OOM 终止程序终止了 oracle
进程。Killed
中大写的 K
指示由 -9
信号终止了进程,通常这一迹象表明此操作可能由 OOM 终止程序完成。
grep -i kill /var/log/messages*
host kernel: Out of Memory: Killed process 2592 (oracle).
我们还会检查系统中低端内存和高端内存的占用状态。需要注意的是,这些值是实时值,会随着系统负载变化,因此,在出现内存不足的情况之前需要频繁监视这些值。在某个进程被终止之后查看这些值不会提供太多信息,因此,对调查 OOM 问题的起因也不会有真正帮助。
[root@test-sys1 ~]# free -lm
total used free shared buffers cached
Mem: 498 93 405 0 15 32
Low: 498 93 405
High: 0 0 0
-/+ buffers/cache: 44 453
Swap: 1023 0 1023
在此测试虚拟机上,我们有 498 MB 的空闲低端内存。系统没有交换使用情况。-l
开关显示高端内存和低端内存统计信息,-m
开关以 MB 为单位显示输出以便于阅读。
[root@test-sys1 ~]# egrep 'High|Low' /proc/meminfo
HighTotal: 0 kB
HighFree: 0 kB
LowTotal: 510444 kB
LowFree: 414768 kB
通过检查 /proc/memory
并具体查看高端和低端值可以获得相同的数据。但是,通过这种方法,我们无法从输出中获取交换信息,并且输出的单位是 KB。
低端内存是内核可以直接物理访问的内存。高端内存是内核无法直接物理访问的内存,因而需要通过虚拟地址进行映射。在较早的 32 位系统上,由于内存映射到虚拟地址的方式,您可以看到低端内存和高端内存。在 64 位平台上,不再需要虚拟地址空间,所有系统内存都显示为低端内存。
虽然查看 /proc/memory
并使用 free
命令对于了解“此时此刻”的内存使用情况非常有用,但有时候我们需要了解内存在较长一段时间内的使用情况。对于这种情况,vmstat
命令非常有用。
在列表 1 的示例中,我们使用 vmstat
命令每 45 秒查看一次资源,持续 10 次。-S
开关显示表中的数据,-M
开关以 MB 为单位显示输出以便于阅读。如您所见,有进程在使用空闲内存,但在此例中我们尚未进行交换。
[root@localhost ~]# vmstat -SM 45 10
procs -----------memory-------- ---swap-- -----io-- --system-- ----cpu---------
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 221 125 42 0 0 0 0 70 4 0 0 100 0 0
2 0 0 192 133 43 0 0 192 78 432 1809 1 15 81 2 0
2 1 0 85 161 43 0 0 624 418 1456 8407 7 73 0 21 0
0 0 0 65 168 43 0 0 158 237 648 5655 3 28 65 4 0
3 0 0 64 168 43 0 0 0 2 1115 13178 9 69 22 0 0
7 0 0 60 168 43 0 0 0 5 1319 15509 13 87 0 0 0
4 0 0 60 168 43 0 0 0 1 1387 15613 14 86 0 0 0
7 0 0 61 168 43 0 0 0 0 1375 15574 14 86 0 0 0
2 0 0 64 168 43 0 0 0 0 1355 15722 13 87 0 0 0
0 0 0 71 168 43 0 0 0 6 215 1895 1 8 91 0 0
列表 1
vmstat
的输出可使用以下命令重定向到文件。我们甚至可以调整持续时间和次数以监视更长时间。在命令运行期间,我们可随时检查输出文件来查看结果。
在下例中,我们每隔 120 秒查看一次内存,持续 1000 次。通过行末尾的 &
,我们可将其作为一个进程运行并恢复终端。
vmstat -SM 120 1000 > memoryusage.out &
作为参考,列表 2 显示了 vmstat
手册页的一部分,给出有关命令所提供输出的详细信息。这仅是与内存相关的信息;该命令还提供有关磁盘 I/O 和 CPU 使用情况的信息。
Memory
swpd: the amount of virtual memory used.
free: the amount of idle memory.
buff: the amount of memory used as buffers.
cache: the amount of memory used as cache.
inact: the amount of inactive memory. (-a option)
active: the amount of active memory. (-a option)
Swap
si: Amount of memory swapped in from disk (/s).
so: Amount of memory swapped to disk (/s).
列表 2
还有许多其他工具可用于监视内存和系统性能,用于调查这种性质的问题。对于收集一段时间内有关系统性能的特定数据,sar
(系统活动报告程序)和 dtrace
(动态跟踪)等工具非常有用。为了实现更好的监控效果,dtrace
稳定性探针和数据稳定性探针甚至具有针对 OOM 情况的触发器,该触发器在内核根据 OOM 情况终止进程时触发。有关 dtrace
和 sar
的详细信息,请参见本文中的“另请参阅”部分。
除了由于工作负载造成的系统 RAM 不足以及交换空间不足等情况外,还有许多其他情况可能导致 OOM 事件。由于系统上的工作负载类型,内核可能无法以最佳方式利用交换空间。对于使用 mlock
() 或 HugePages 的应用,在系统的物理内存开始不足时,这些应用的内存无法交换到磁盘。内核数据结构也可能会占用过多空间,耗尽系统上的内存,导致出现 OOM 情况。许多基于 NUMA 架构的系统出现 OOM 情况是因为,一个节点内存不足触发了内核中的 OOM,然而其余节点中还留有充足的内存。有关使用 NUMA 架构的计算机各种 OOM 情况的详细信息,请参阅本文中的“另请参阅”部分。
配置 OOM 终止程序
Linux 上的 OOM 终止程序有多个配置选项,允许开发人员选择系统在面临内存不足情况时的行为表现。根据环境以及系统上配置的应用,这些设置和选项会有所不同。
注意:建议首先在开发环境中进行测试和调整,然后再对重要生产系统进行更改。
在系统运行单个关键任务的一些环境中,一种可行的选择措施是在系统发生 OOM 情况时重新启动,以快速将系统恢复到正常运行状态,无需管理员的干预。虽然这并非最佳方法,不过其中的逻辑是,如果由于 OOM 终止程序终止了应用导致其无法运行,但其在系统启动时启动,则重新启动系统可恢复该应用。如果该应用由管理员负责手动启动,则此措施不起作用。
以下设置将导致系统发生严重错误并在出现内存不足情况时重新启动。sysctl
命令会实时设置此项,将设置附加到 sysctl.conf
可在重新启动后保留这些设置。kernel.panic
的 X
表示系统重新启动前的秒数。应对此设置进行调整以满足环境的需求。
sysctl vm.panic_on_oom=1
sysctl kernel.panic=X
echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf
我们还可以优化 OOM 终止程序处理特定进程中 OOM 情况的方式。以之前终止的 oracle
进程 2592 为例。如果要减少 OOM 终止程序终止 oracle
进程的可能性,我们可执行以下操作。
echo -15 > /proc/2592/oom_adj
通过执行以下操作,我们可增加 OOM 终止程序终止 oracle
进程的可能性。
echo 10 > /proc/2592/oom_adj
如果要使 oracle
进程不受 OOM 终止程序的影响,我们通过以下操作使其完全不受 OOM 终止程序的影响。需要注意的是,根据系统的资源和配置,这可能会导致意外的行为。如果内核无法终止某个使用了大量内存的进程,就会转为终止其他可用进程。而这样的一些进程可能是重要的操作系统进程,在终止后最终会导致系统关闭。
echo -17 > /proc/2592/oom_adj
我们可以为 oom_adj
设置从 -16
到 +15
的有效范围,设置 -17
会使某个进程完全不受 OOM 终止程序的影响。该数字越大,系统出现 OOM 情况时就越有可能选择终止我们的进程。您还可以查看 /proc/2592/oom_score
的内容,确定 OOM 终止程序终止某个进程的可能性。分值为 0
表示我们的进程不受 OOM 终止程序的影响。OOM 分值越高,某进程在 OOM 情况下被终止的可能性就越高。
使用以下命令可完全禁用 OOM 终止程序。建议不要在生产环境中这样做,因为在真实出现内存不足情况时,可能会出现意外行为,具体取决于可用的系统资源和配置。这种意外行为可能是从内核严重错误到挂起之类的任何情况,具体取决于出现 OOM 情况时内核可用的资源。
sysctl vm.overcommit_memory=2
echo "vm.overcommit_memory=2" >> /etc/sysctl.conf
对于一些环境,这些配置选项不一定合适,因而需要进一步的优化和调整。根据系统上运行的应用的需求,为内核配置 HugePages 有助于解决 OOM 问题。