认识OOM Killer - 记一次MySQL挂掉的领悟

Posted by jintang on 2017-10-12

国庆假期刚过,还在假期后遗症中。公司的内部测试服务器配的MySQL不给了,给我挂了好几次。

查看一下系统日志:

1
tail -1000 /var/log/messages | grep mysqld

发现Out of memory: Kill process 129382 (mysqld) score 9 or sacrifice child

1
Out of memory: Kill process 129382 (mysqld) score 9 or sacrifice child

大概就知道是内存不足导致的。心想着这台服务器硬件太低了吧,想着换一台机器算了。

但是怀着一探究竟的精神,百度了一下这个错误,果然发现一个叫做OOM Killer的东西。

Linux 内核有个机制叫OOM killer(Out Of Memory killer),该机制会监控那些占用内存过大,尤其是瞬间占用内存很快的进程,然后防止内存耗尽而自动把该进程杀掉。

OOM Killer的触发

下面我们模拟一个场景,用一个很吃内存的进程,耗尽所有内存

先查看我们的内存

1
2
3
4
5
[root@centos65 ~]# free -m
total used free shared buffers cached
Mem: 980 87 893 0 0 3
-/+ buffers/cache: 83 897
Swap: 1983 13 1970

显示我有1G的内存,可用内存有900M左右,交换分区有2G

现在执行dd吃掉内存:

1
2
[root@hostname www]# dd if=/dev/zero of=/dev/null bs=2000M

再次查看内存情况:

1
2
3
4
5
[root@centos65 ~]# free -m
total used free shared buffers cached
Mem: 980 927 53 0 0 1
-/+ buffers/cache: 925 55
Swap: 1983 1179 804

当内存没有了,就会使用swap虚拟内存,此时系统已经非常慢了。

关掉交换分区

1
swapoff -a

再次查看内存:

1
2
3
4
5
[root@centos65 ~]# free -m
total used free shared buffers cached
Mem: 981 118 863 0 2 10
-/+ buffers/cache: 105 876
Swap: 0 0 0

swap已经为0, 再次执行dd吃掉内存:

1
2
[root@hostname www]# dd if=/dev/zero of=/dev/null bs=890M
Killed

发现进程被Kill掉了

查看日志:

1
2
3
4
tail -f /var/log/messages | grep "Out of memory"
...
Out of memory: Kill process 38712 (dd) score 712 or sacrifice child
...

MySQL关于对SWAP分区的思考

使用交换分区能够防止mysqld进程被kill掉,但是由于当系统内存不足了,使用swap会将一些虚拟内存写到磁盘的交换区中这样就会发生内存交换。一旦发生内存交换,对mysql会有灾难性的影响。

所以究竟要不要使用swap,其实还是有争议的,个人感觉不要使用比较好:

  1. 公有云上的机器基本都没有交换分区
  2. 机器的内存应该在超过一定的百分比后的时候进行告警,及时处理,就可以避免mysqld因内存不足被kill的问题

关闭swap可以使用设置内核参数: vm.swappiness=0;

延伸阅读

更多防止oom killer杀掉mysqld进程的方案:

参考:

http://linuxperf.com/?p=94