OOM Killer - 杀死 MySQL 服务器

pra*_*tri 11 linux mysql out-of-memory

在我们的一个 MySQL master 上,OOM Killer 被调用并杀死了 MySQL 服务器,导致大停电。以下是内核日志:

[2006013.230723] mysqld invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0
[2006013.230733] Pid: 1319, comm: mysqld Tainted: P           2.6.32-5-amd64 #1
[2006013.230735] Call Trace:
[2006013.230744]  [<ffffffff810b6708>] ? oom_kill_process+0x7f/0x23f
[2006013.230750]  [<ffffffff8106bde2>] ? timekeeping_get_ns+0xe/0x2e
[2006013.230754]  [<ffffffff810b6c2c>] ? __out_of_memory+0x12a/0x141
[2006013.230757]  [<ffffffff810b6d83>] ? out_of_memory+0x140/0x172
[2006013.230762]  [<ffffffff810baae8>] ? __alloc_pages_nodemask+0x4ec/0x5fc
[2006013.230768]  [<ffffffff812fca02>] ? io_schedule+0x93/0xb7
[2006013.230773]  [<ffffffff810bc051>] ? __do_page_cache_readahead+0x9b/0x1b4
[2006013.230778]  [<ffffffff810652f8>] ? wake_bit_function+0x0/0x23
[2006013.230782]  [<ffffffff810bc186>] ? ra_submit+0x1c/0x20
[2006013.230785]  [<ffffffff810b4e53>] ? filemap_fault+0x17d/0x2f6
[2006013.230790]  [<ffffffff810cae1e>] ? __do_fault+0x54/0x3c3
[2006013.230794]  [<ffffffff812fce29>] ? __wait_on_bit_lock+0x76/0x84
[2006013.230798]  [<ffffffff810cd172>] ? handle_mm_fault+0x3b8/0x80f
[2006013.230803]  [<ffffffff8103a9a0>] ? pick_next_task+0x21/0x3c
[2006013.230808]  [<ffffffff810168ba>] ? sched_clock+0x5/0x8
[2006013.230813]  [<ffffffff81300186>] ? do_page_fault+0x2e0/0x2fc
[2006013.230817]  [<ffffffff812fe025>] ? page_fault+0x25/0x30
Run Code Online (Sandbox Code Playgroud)

这台机器有64GB RAM。

以下是 mysql 配置变量:

innodb_buffer_pool_size        = 48G
innodb_additional_mem_pool_size = 512M
innodb_log_buffer_size         = 64M
Run Code Online (Sandbox Code Playgroud)

除了一些 nagios 插件和指标收集脚本外,这台机器上没有其他任何东西可以运行。有人可以帮我找出为什么 OOM 杀手被调用以及我如何防止它在未来被调用。有什么办法可以告诉 OOM 杀手不要杀死 mysql 服务器。我知道我们可以将oom_adj一个进程的值设置得非常小,以防止它被 OOM 杀手杀死。但是有没有其他方法可以防止这种情况发生。

Adr*_* M. 26

Linux 会过度使用内存。这意味着它允许进程请求比系统上实际可用的更多的内存。当程序尝试 malloc() 时,内核会说“好的,您获得了内存”,但不要保留它。只有当进程将在此空间中写入内容时才会保留内存。

要查看差异,您有 2 个指标:虚拟内存和驻留内存。Virtual 是进程请求的内存,Resident 是进程真正使用的内存。

使用此系统,您可能会进入“超额预订”状态,内核授予的内存多于可用内存。然后,当您的系统进行 0 字节的空闲内存和 Swap 时,他必须牺牲(杀死)一个进程来获得空闲内存。

这就是 OOM Killer 开始行动的时候。OOM 根据他的内存消耗和许多其他因素选择一个进程(父进程获得其子进程分数的 1/2;如果是 root 拥有的进程,分数除以 4,等等。看看Linux- MM.org/OOM_Killer

您可以通过调整/proc/MySQL_PID/oom_adj文件来影响 OOM 评分。通过将其设置为-17,您的进程将永远不会被终止。但在此之前,您应该调整 MySQL 配置文件以限制 MySQL 内存使用。否则,OOM Killer 会杀死其他系统进程(如 SSH、crontab 等),您的服务器将处于非常不稳定的状态,可能导致数据损坏,这比任何事情都糟糕。

此外,您可以考虑使用更多的交换。

[编辑]

您还可以通过以下 2 个 sysctls 更改它的过度使用行为:

vm.overcommit_memory
vm.overcommit_ratio
Run Code Online (Sandbox Code Playgroud)

内核文档中所述

过量使用内存:

此值包含启用内存过量使用的标志。

当此标志为 0 时,内核会尝试估计用户空间请求更多内存时剩余的可用内存量。

当此标志为 1 时,内核假装总是有足够的内存,直到实际用完为止。

当此标志为 2 时,内核使用“永不过度使用”策略来尝试防止任何内存过度使用。请注意, user_reserve_kbytes 会影响此策略。

这个特性非常有用,因为有很多程序使用 malloc() 大量内存“以防万一”并且不使用太多内存。

默认值为 0。

有关更多信息,请参阅文档/vm/overcommit-accounting 和 security/commoncap.c::cap_vm_enough_memory()。

过量使用比率:

当 overcommit_memory 设置为 2 时,提交的地址空间不允许超过 swap 加上物理 RAM 的这个百分比。看上面。

[/编辑]