默认关闭Linux OOM杀手吗?


37

Linux上的OOM杀手经常对各种应用程序造成破坏,并且似乎并没有在内核开发方面做太多改进。作为设置新服务器的最佳实践,将内存过量使用的默认设置反转为默认值,也就是将其关闭(vm.overcommit_memory=2),除非您知道要为特定用途打开它,否则会更好吗?在您知道要过度使用的情况下,这些用例将是什么?

另外,由于行为vm.overcommit_memory=2取决于vm.overcommit_ratio和交换空间,因此,调整后两者的大小以使整个设置合理地工作将是一个很好的经验法则吗?

Answers:


63

一个有趣的类比(来自http://lwn.net/Articles/104179/):

一家飞机公司发现,用较少的燃油驾驶飞机便宜。飞机将更轻,使用的燃料更少,从而节省了金钱。然而,在极少数情况下,燃油量不足,飞机将坠毁。该公司的工程师通过开发特殊的OOF(燃料不足)机制解决了该问题。在紧急情况下,一名乘客被选中并被赶出飞机。(在必要时,重复该程序。)发展了大量理论,许多出版物致力于适当选择要被驱逐的受害者的问题。应该随机选择受害者吗?还是应该选择最重的人?还是最古老的?如果乘客付款以免被驱逐出境,这样受害者将是船上最贫穷的人?举例来说,如果选择了最重的人,那么在飞行员的情况下是否应该有一个特殊的例外?是否应该豁免头等舱乘客?现在,OOF机制已经存在,它将不时地被激活,即使在没有燃油短缺的情况下,也可以将乘客赶出。工程师们仍在精确地研究这种故障是如何引起的。


11
我非常喜欢,感谢您对此进行了深入研究。
尼克·博尔顿

32

仅当系统过载时,OOM杀手才会造成严重破坏。给它足够的交换空间,不要运行突然决定要消耗大量RAM的应用程序,这样就不会有问题。

具体回答您的问题:

  • 我认为在一般情况下关闭过量使用并不是一个好主意。编写很少的应用程序来正确处理brk(2)(以及使用它的包装程序,例如malloc(3))返回错误。当我在上一份工作中对此进行试验时,要使所有功能都能够处理内存不足错误,而不是仅仅为了处理OOM的后果(在我们的案例中,是,这很麻烦)。这比发生OOM时必须重新启动偶尔的服务要糟糕得多-我们必须重新启动整个集群,因为GFS是一大堆粪便。
  • 您想对任何过量使用内存的进程进行过量使用。这里的两个最常见的罪魁祸首是Apache和JVM,但是许多应用程序或多或少都在这样做。他们认为他们将来可能会需要很多内存,因此他们马上就抢了一大块。在启用了过量提交的系统上,内核会“无论如何,当您实际要写入这些页面时都会打扰我”,并且不会发生任何不良情况。在过度使用的系统上,内核说:“不,您不能拥有那么多的内存,如果您确实碰巧在将来某个时候将其全部写入,那么您就没有内存了!” 并且分配失败。由于没有然后出现“哦,好的,我可以有这么少的过程数据段吗?”,然后该过程要么(a)出现内存不足错误退出,要么(b)不检查来自以下位置的返回代码malloc,认为可以,然后将其写入无效的内存位置,从而导致段错误。值得庆幸的是,JVM在启动时就完成了所有的预分配操作(因此,您的JVM要么立即启动,要么立即死亡,这通常会引起注意),但是Apache对每个新子对象都进行了一些时髦的处理,这会对生产产生令人兴奋的影响(不可复制的“不处理连接” ”)。
  • 我不想将我的overcommit_ratio设置为高于默认值50%。再次,从我的测试来看,虽然将其设置为80或90 听起来很不错,但内核在不方便的时间需要大块内存,并且具有高过载率的满载系统可能没有足够的备用内存当内核需要它时(导致恐惧,瘟疫和呕吐)。因此,使用过量提交会引入一种新的,甚至更有趣的故障模式-而不是仅在内存耗尽时重新启动任何发生OOM的进程,现在您的计算机就会崩溃,从而导致计算机上所有组件的中断。真棒!
  • 免过量使用系统中的交换空间取决于应用程序需要多少请求但未使用的内存,以及良好的安全裕度。算出特定情况下的需求留给读者练习。

基本上,我的经验是,关闭过量使用是一个不错的实验,实际上在理论上听起来不那么有效。这很好地与我的经验对应与内核其他可调参数- Linux内核开发者几乎总是比你聪明的,默认的工作最适合广大,广大大多数情况下。别管它们,而是去查找导致泄漏的过程并进行修复。


2
我不希望我的备份过程被杀死,因为有人正在对我的Web服务器进行DoS处理。例外很好,但是默认值应该是安全性和一致性。像OOM这样的优化应该手动打开恕我直言。就像编码一样,您可以干净地编码,然后进行优化。过量提交是一个不错的功能,但不应作为默认功能。
Aki

1
如果您不希望由于有人对您的Web服务器进行DoS而导致您的备份过程被杀死,请不要以DoS可能导致系统资源不堪重负的方式配置Web服务器。
womble

我有8GB的RAM,仅运行Firefox,而虚拟机有时会导致OOM杀手杀死虚拟机。编译虚幻引擎4时,每个clang调用都会占用1〜1.5GB的内存,而OOM杀手会不时地杀死一个。现在,我对此基本满意,如果没有OOM杀手,他们可能仍然会断断续续。只是每一次OOM杀手想要杀死一个进程时,我的系统都会冻结10分钟,然后该恶意进程才被杀死。虫子?最有可能的。我要吗?当然不。这就是您可能要禁用OOM杀手的原因。
Shahbaz

1
如果要在一个盒子上进行所有这些操作,则需要更多的RAM,并且禁用过量使用只会使情况变得更糟。
Ben Lutgens,2015年

6

嗯,我并没有完全赞成过分使用和OOM杀手的说法。

“ OOM杀手只会在系统过载的情况下造成破坏。给它足够的交换空间,不要运行突然决定要消耗大量RAM的应用程序,这样就不会有问题。”

他的目的是描述一个环境场景,其中不强制执行过量使用和OOM杀手,或者不“真正”采取行动(如果所有应用程序均按需分配了内存,并且有足够的虚拟内存可分配,则内存写入将紧随内存分配而不会错误,因此即使启用了过量使用策略,我们也无法真正谈论过量使用的系统)。这是关于一种隐式承认,即过度使用和OOM杀手在不需要他们干预时效果最佳,就我所知(我承认我不能说太多...),该策略的大多数支持者都以某种方式同意这一点。Morover,指的是在预分配内存时具有特定行为的应用程序,这使我认为可以在分布级别上调整特定的处理方式,而不是使用默认值,

对于JVM而言,它是一台虚拟机,在某种程度上,它需要分配启动时所需的所有资源,因此它可以为其应用程序创建其“伪”环境,并使可用资源与主机分离环境,尽量。因此,最好是使它在启动时失败,而不是由于“外部” OOM条件(由过量提交/ OOM杀手/其他原因导致)或由于这种条件干扰其自身而导致的一段时间后才失败内部OOM处理策略(通常,VM应该从一开始就获得任何必需的资源,而主机系统应“忽略”它们直到结束,就像永远不会-并且不能与图形卡共享任何数量的物理RAM一样) -被操作系统感动)。

关于Apache,我怀疑让整个服务器偶尔被终止和重启是否比让单个子项和单个连接从其(=子项/连接的)开始(就像它是一个全新的实例)失败就更好了。在另一个实例运行一段时间后创建的JVM)。我想最好的“解决方案”可能取决于特定的上下文。例如,考虑到电子商务服务,有时与购物图的一些连接随机失败而不是失去整个服务可能会更可取,例如冒着中断进行中的订单敲定的风险,或者(可能会更糟)付款过程,并承担该案件的所有后果(可能无害,但可能有害)-当然,当问题出现时,

同样,在工作站上消耗最多资源的过程(因此成为OOM杀手的首选)可能是内存密集型应用程序,例如视频转码器或渲染软件,可能是唯一的应用程序用户想要保持原样。这些注意事项提示我,OOM杀手默认策略过于激进。它使用一种“最差拟合”方法,该方法在某种程度上类似于某些文件系统(OOMK尝试并释放尽可能多的内存,同时减少被杀死的子进程的数量,以防止在短时间内进行进一步干预,因为以及fs可以为某个文件分配比实际需要更多的磁盘空间,以防止在文件增长时进行任何进一步分配,从而在某种程度上防止碎片。

但是,我认为相反的策略(例如“最合适”的方法)可能更可取,这样可以释放特定点所需的确切内存,而不用为“大”过程打扰,因为这可能很浪费内存,但也可能不知道,内核无法知道(嗯,我可以想像一下,跟踪页面访问次数和时间可以暗示某个进程是否正在分配内存,因此不再需要它,因此可以猜测一个进程是否浪费内存或只是浪费大量内存,但应根据cpu周期对访问延迟进行加权,以将内存浪费与内存 cpu密集型应用程序区分开来,但是尽管可能不准确,但这种启发式方法可能会产生过多开销。

而且,杀死尽可能少的进程永远不是一个好选择。例如,在台式机环境(例如,以示例为例的上网本或资源有限的上网本)中,用户可能正在运行带有多个选项卡的浏览器(因此,内存消耗大-假设这是OOMK的首要选择) ,再加上其他一些应用程序(带有未保存数据的文字处理器,邮件客户端,pdf阅读器,媒体播放器等),再加上一些(系统)守护程序,再加上一些文件管理器实例。现在,发生OOM错误,并且当用户在网络上执行被认为“重要”的操作时,OOMK选择终止浏览器……用户将感到失望。另一方面,关闭少数文件管理器

无论如何,我认为应该使用户能够自己决定要做什么。在台式机(=交互式)系统中,这应该相对容易做到,只要保留了足够的资源来要求用户关闭任何应用程序(但即使关闭几个选项卡也足够)并处理其选择(一个选项可以如果有足够的空间,则包括创建一个附加的交换文件)。对于服务(以及一般而言),我还考虑了两项可能的增强功能:一种是记录OOM杀手干预,以及以易于调试的方式启动/分叉故障的进程(例如,API可以通知发布新流程创建或派生的流程-因此,具有适当补丁的Apache之类的服务器可以为某些错误提供更好的日志记录);这可以独立于过度使用/ OOMK来完成;第二,但不是很重要,可以建立一种机制来微调OOMK算法-我知道在某种程度上可以逐个过程地定义特定策略是可行的,但是我的目标是基于应用程序名称(或ID)的一个或多个列表的“集中式”配置机制,以识别相关进程并赋予它们一定程度的重要性(根据列出的属性);这种机制也应该(或至少可以)分层,以便可以有一个顶级的用户定义列表,一个系统(分布)定义的列表以及(底层)应用程序定义的条目(因此,例如,DE文件管理器可以指示OOMK安全地杀死任何实例,

更进一步,可以提供一个API,以允许应用程序在运行时提高或降低其“重要性”级别(就内存管理目的和执行优先级而言),例如,字处理器可以以低的“重要性”,但随着刷新到文件或执行写操作之前保存一些数据的重要性而提高,一旦这种操作结束,重要性再次降低(类似地,当文件管理器从将文件点亮以处理数据,反之亦然,而不是使用单独的进程,Apache可以为不同的子级赋予不同级别的重要性,或者根据sysadmin决定并通过Apache或任何其他类型的服务器公开的某些策略来更改子级状态。 -设置)。当然,这样的API可能并且将被滥用/滥用,但是与内核任意杀死进程以释放内存而没有关于系统运行情况的任何相关信息(以及内存消耗/创建时间等)相比,我认为这是个小问题。 (对我而言,“相关性不足或无法验证”)-只有用户,管理员和程序编写者才能真正确定由于某种原因,是否仍需要某个过程,原因是什么和/或该应用程序是否处于领先状态导致数据丢失或其他损坏/麻烦;但是,仍可以做出一些假设,例如,查找进程获取的某种类型的资源(文件描述符,网络套接字等),并通过未决的操作可以判断出该进程是否应处于比其更高的“状态”一套

或者,只需避免过度使用,让内核执行内核必须做的事情,分配资源(但不要像OOM杀手那样随意地拯救资源),安排进程,防止饥饿和死锁(或从中拯救),确保完全抢占和内存空间分离,等等。

我还会花更多的时间谈论过量使用方法。在其他讨论中,我提出了关于过量使用的主要担忧之一(既是想要它的原因,又是可能造成麻烦的原因)包括分叉处理:说实话,我不知道复制的确切含义是-已实施了写入策略,但我认为任何积极(或乐观)的策略都可以通过类似于交换的本地策略来缓解。也就是说,不仅可以克隆(并调整)分支的过程代码页和调度结构,还可以在实际写入之前复制其他一些数据页,在父进程访问的那些页中进行选择以更频繁地进行写入(即,使用计数器进行写操作)。

一切,当然,恕我直言。


5
“更重要的是,可以提供一个API,以允许应用程序在运行时提高或降低其'重要性'级别/proc/$PID/oom_adj。”
六。

1
关于JVM,有些陷阱使您在某些情况下希望内存过量使用:如果要从原始JVM创建另一个JVM,它将调用fork()。fork调用将分配与原始进程(第一个)一样多的内存,直到它真正启动该进程为止。因此,假设您有一个4GB的JVM,并想从中创建一个新的512KB JVM,除非您超量使用,否则您将需要8GB的内存来进行此操作……
alci

4
@Vi。现在似乎是/proc/$PID/oom_score_adj
erm3nda 2015年

1

如果您的内存被进程彻底耗尽,可能会威胁到系统的稳定性,那么OOM杀手into可危。OOM Killer的任务是杀死进程,直到释放足够的内存以使其余进程顺利运行为止。OOM杀手必须选择“最佳”程序来杀死。此处的“最佳”是指在终止时将释放最大内存的过程,并且对系统而言也最不重要。主要目标是杀死最少数量的进程,以最大程度地减少造成的损害,同时最大程度地释放所释放的内存。为方便起见,内核为每个进程维护oom_score。您可以在pid目录下的/ proc文件系统中看到每个进程的oom_score

# cat /proc/10292/oom_score

任何进程的oom_score值越高,在内存不足的情况下被OOM Killer杀死的可能性就越高。

信誉:-Linux内核正在启动OOM杀手

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.