EDIT2:这个问题在 3.8.0-25-generic #37-Ubuntu SMP 下似乎也存在
编辑:我修改了原标题“为什么用 dd 写入文件会触发 Linux 内存不足管理器”中的问题?为了更好地反映我担心下面描述的一般问题:
我遇到了一个麻烦的场景,当我编写一个大小超过内存限制(设置为 300MB)的文件时,OOM 杀手很难杀死我的 LXC 容器中的进程。当我在实际只有 512 MB RAM 的 Xen 虚拟机(EC2 t1.micro)上运行应用程序时,不会出现该问题,因此文件缓冲似乎存在一些与容器内存限制相关的问题。
作为一个简单的例子,我可以演示 dd 写入的大文件如何导致问题。同样,这个问题困扰着所有应用程序。我正在寻求解决应用程序缓存变得太大的一般问题;我了解如何使“dd”工作。
设想:
我有一个 LXC 容器,其中 memory.limit_in_bytes 设置为 300 MB。
我尝试添加一个 ~500 MB 的文件,如下所示:
dd if=/dev/zero of=test2 bs=100k count=5010
Run Code Online (Sandbox Code Playgroud)
大约 20% 的时间,Linux OOM 管理器被此命令触发并杀死一个进程。不用说,这是非常意外的行为;dd 旨在模拟由在容器内运行的程序写入的实际“有用”文件。
详细信息:虽然文件缓存变大 (260 MB),但 rss 和文件映射似乎仍然很低。以下是 memory.stat 在写入过程中可能是什么样子的示例:
cache 278667264
rss 20971520
mapped_file 24576
pgpgin 138147
pgpgout 64993
swap 0
pgfault 55054
pgmajfault 2
inactive_anon 10637312
active_anon 10342400
inactive_file 278339584
active_file 319488
unevictable …Run Code Online (Sandbox Code Playgroud) 有没有办法获得核心转储或能够调试已被 oom-killer 杀死的进程?
或者甚至设置 oom-killer 来尝试使用 ABRT 来终止进程?
我的团队在尝试进行由 OutOfMemoryErrors 触发的良好堆转储时遇到了困难。出于特定原因,我们目前正在使用从 bash 脚本调用的 jmap 进行转储,而不是使用 HeapDumpOnOutOfMemoryError 标志。我们使用的是 64 位 1.6 JVM,堆大小约为 3 GB。我们的堆转储失败 90% 的时间(猜测)。
有什么我们可以做的事情来提高我们获得干净的堆转储的几率,我们可以用它来解决内存问题吗?我已经读到 jmap 在 Java 1.4 中存在重大问题,但现在应该主要解决这些问题。
我正在调查为什么我们的两个进程被 Linux OOM 杀手杀死 - 尽管似乎有足够的 RAM 和大量可用的 SWAP。
当我通过这个答案解释它时,第一个内存请求要求 2^2=4 页(16KB)的内存(顺序标志)并希望它来自“正常”区域。
Jan 27 04:26:14 kernel: [639964.652706] java invoked oom-killer: gfp_mask=0x26000c0, order=2, oom_score_adj=0
Run Code Online (Sandbox Code Playgroud)
如果我正确解析输出,就会有足够的空间:
Node 0 Normal free:178144kB min:55068kB low:68832kB high:82600kB
Run Code Online (Sandbox Code Playgroud)
几分钟后第二次有同样的请求——而且似乎也有足够的可用空间。
为什么当时触发了OOM杀手?我解析的信息有误吗?
vm.overcommit_memory设置设置为“0”(启发式),这可能不是最佳的。实例一:
Jan 27 04:26:14 kernel: [639964.652706] java invoked oom-killer: gfp_mask=0x26000c0, order=2, oom_score_adj=0
Jan 27 04:26:14 kernel: [639964.652711] java cpuset=/ mems_allowed=0
Jan 27 04:26:14 kernel: [639964.652716] CPU: 5 PID: 2152 Comm: java Not tainted 4.4.0-59-generic …Run Code Online (Sandbox Code Playgroud) Ubuntu 的 Out-Of-Memory Killer 对我的服务器造成了严重破坏,悄悄地暗杀了我的应用程序、sendmail、apache 和其他应用程序。
我已经设法了解了 OOM 杀手是什么,以及它的“坏”规则。虽然我的机器很小,但我的应用程序更小,通常只有一半的物理内存在使用,更不用说交换空间了,所以我很惊讶。我试图找出罪魁祸首,但我不知道如何阅读 OOM-Killer 日志。
任何人都可以指点我如何阅读日志中的数据的教程(什么是ve,free和gen?),或者帮我解析这些日志?
Apr 20 20:03:27 EL135 kernel: kill_signal(13516.0): selecting to kill, queued 0, seq 1, exc 2326 0 goal 2326 0...
Apr 20 20:03:27 EL135 kernel: kill_signal(13516.0): task ebb0c6f0, thg d33a1b00, sig 1
Apr 20 20:03:27 EL135 kernel: kill_signal(13516.0): selected 1, signalled 1, queued 1, seq 1, exc 2326 0 red 61795 745
Apr 20 20:03:27 EL135 kernel: kill_signal(13516.0): selecting to kill, queued 0, …Run Code Online (Sandbox Code Playgroud) 我们有一个 debian linux 网络服务器。它只是运行 apache2。我们的 mysql 服务器在另一台主机上。然而,我们有时会在网络服务器上运行 cron 任务来执行常规任务。
然而,最近一个 cron 任务出现了一个错误,并开始吞噬内存。Linux OOM 杀手杀死了 apache。这当然导致我们的网站瘫痪。内存饥渴的 cron 继续运行。但是在这种情况下,我希望 OOM 杀手杀死该脚本,而不是apache。
有什么方法可以配置内核,以便我可以说不要杀死名为“apache2”的进程(或者至少让 apache2 成为它杀死的最后一件事)?apache 和常规 cron 都以同一用户 (www-user) 运行。
我正在运行 Apache 网络服务器,并希望稍微改进 OOM 情况的处理方式。
我很了解 OOM 分数,并且已经在这方面进行了一些自定义,因此当发生不好的事情时,Linux 会终止正确的进程。但这还不够。
问题是,有时当发生 OOM 时,服务器会过载,然后崩溃,必须重新启动。我想在不完全重启服务器的情况下处理这个问题。所以我需要以某种方式在 OOM 杀手调用上“挂钩”一个脚本,这将杀死所有 apache(及其 CGI)进程,从而释放内存并再次启动它(Apache)。
我知道这会起作用,因为如果发生 OOM 并且我足够快地登录到服务器并手动终止 Apache,那么一切都会好起来的。
仅供参考,我现在正在运行将近一百个这样的网络服务器,这就是我寻找全自动解决方案的原因。
一种可能的解决方案当然是使用一些看门狗来解析系统日志并以这种方式检测 OOM - 我已经有了类似的东西,它通过电子邮件通知 OOM 杀人事件。这种方法可以解决某些情况,但如果 OOM 真的很糟糕,服务器过载太多,我的脚本甚至无法启动(由 cron 运行)。可以通过使用 inotify 观察系统日志或通过管道直接(即通过 fifo)将系统日志传送到脚本来改进它。
但我仍然想知道 - 有没有办法将脚本直接“挂钩”到 OOM 杀手上?所以我会把类似的东西放在一些 /etc/.. 文件中:
oom_action="sh /path/to/my/script.sh kill"
Run Code Online (Sandbox Code Playgroud)
或者它根本不可能那样做?
我使用 Centos 6、Apache 2.2 和 PHP 作为 FastCGI。
我正在运行带有 i2p 和 Tor 的 ARM 路由器 - Netgear R7000。当然,我已经向它添加了完整的 512 MB 的 SWAP 以防止 OOM,我知道它可能会减慢系统速度……但是我仍然可以从大量免费的 SWAP 开始获得 OOM 杀手,并杀死 Tor!更有趣的是,在杀死tor之后,系统似乎可以无限期地运行……但似乎仍然无法交换tor。我什至试图关闭过度使用,但根本没有帮助。
请参阅下面的 dmesg 日志
resetbutton invoked oom-killer: gfp_mask=0x2000d0, order=0, oom_score_adj=0
CPU: 0 PID: 1500 Comm: resetbutton Tainted: P 3.10.79 #381
Backtrace:
[<c0015cb8>] (dump_backtrace+0x0/0x118) from [<c0015ec0>] (show_stack+0x18/0x1c)
r6:c7a4cdc0 r5:00000000 r4:c6818000 r3:00000000
[<c0015ea8>] (show_stack+0x0/0x1c) from [<c012e5c0>] (dump_stack+0x24/0x28)
[<c012e59c>] (dump_stack+0x0/0x28) from [<c007c5cc>] (dump_header.isra.13+0x84/0x194)
[<c007c548>] (dump_header.isra.13+0x0/0x194) from [<c007c958>] (oom_kill_process+0x90/0x3e8)
[<c007c8c8>] (oom_kill_process+0x0/0x3e8) from [<c007d17c>] (out_of_memory+0x2c0/0x304)
[<c007cebc>] (out_of_memory+0x0/0x304) from [<c007fcbc>] (__alloc_pages_nodemask+0x5b0/0x694)
[<c007f70c>] (__alloc_pages_nodemask+0x0/0x694) from [<c00a2464>] (cache_alloc_refill+0x2c8/0x600) …Run Code Online (Sandbox Code Playgroud) 我被要求fio为这个测试数据集提供基准测试结果:1048576x1MiB。因此,整体大小为1TiB。该集合包含2^20 个 1MiB文件。服务器运行CentOS Linux release 7.8.2003 (Core)。它有足够的内存:
[root@tbn-6 src]# free -g
total used free shared buff/cache available
Mem: 376 8 365 0 2 365
Swap: 3 2 1
Run Code Online (Sandbox Code Playgroud)
它实际上不是物理服务器。相反,它是一个具有以下 CPU 的 Docker 容器:
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 48
On-line CPU(s) list: 0-47
Thread(s) per core: 2
Core(s) per socket: 12
Socket(s): 2
NUMA node(s): 2
Vendor ID: GenuineIntel
CPU family: 6
Model: 85 …Run Code Online (Sandbox Code Playgroud) 我有标准的“开箱即用”安装
Linux version 3.0.1.stk64 (dfn@localhost.localdomain) (gcc version 4.5.1 20100924 (Red Hat 4.5.1-4) (GCC) ) #1 SMP Sat Aug 13 12:53:46 EDT 2011
Run Code Online (Sandbox Code Playgroud)
它已将 postgresql 8.4 安装为(启动脚本)
/etc/init.d/postgresql
Run Code Online (Sandbox Code Playgroud)
数据目录
/etc/postgresql/8.4/main/
Run Code Online (Sandbox Code Playgroud)
我的问题是有时内核决定在内存不足时杀死一些 Postgresql 进程。我想通知内核,不应选择杀死 Postgresql。我从 postgresql 文档(http://www.postgresql.org/docs/9.1/static/kernel-resources.html)中读到,echo -17 > /proc/self/oom_adj可以使用命令行来避免杀死。
我试图将此命令行添加到/etc/init.d/postgresql脚本中,但真的不知道将它放在哪里。
任何指示如何去做?顺便说一句,scipt ( /etc/init.d/postgresql) 是:
#!/bin/sh
set -e
### BEGIN INIT INFO
# Provides: postgresql
# Required-Start: $local_fs $remote_fs $network $time
# Required-Stop: $local_fs $remote_fs $network $time
# Should-Start: $syslog
# Should-Stop: $syslog
# Default-Start: …Run Code Online (Sandbox Code Playgroud)