最近在项目里遇到这样一个问题:
应用部署在线下服务器上,线下服务器,相对来说配置低一些,同时可能和其它的服务部署在一起。
后来遇到一个比较怪异的问题:
应用跑一段时间,Tomcat进程就挂掉了。
而且这个没有什么规律,不是在特定操作执行时,或者特定时间出现。同时没有任何的日志。本来以为是其它的服务的人把我们的不小心kill掉了,但kill的有点太频繁了,同时和QA同学了解到,在线下服务器上的其他服务,目前都没有操作过,排除了人为的可能。
剩下的就只能从应用自身的问题入手了。但整个进程挂掉的时候,并没有任何日志生成,同时也没有生成Crash文件。还尝试在启动脚本中增加
-XX:+HeapDumpOnOutOfMemoryError,想要分析下堆内数据,进程退出时也是什么都没生成。
这时就只能请教万能的网络了,Google之后了解到一个Linux OOM Killer。按照这个思路和提供的方式去查看了服务器的日志,果然问题在这儿。
Linux OOM Killer
在这里有一个关于OOM Killer的描述
It is the job of the linux ‘oom killer’ to sacrifice one or more processes in order to free up memory for the system when all else fails. It will also kill any process sharing the same mm_struct as the selected process, for obvious reasons. Any particular process leader may be immunized against the oom killer if the value of its /proc//oomadj is set to the constant OOM_DISABLE (currently defined as -17).
长话短说就是,Linux Kernel的这个Killer,会在内存不足的时候kill掉任何 不受保护的进程,从而释放内存,保证Kernel的运行。
要让自己的进程成为一个受保护的进程,请注意这一句:
Any particular process leader may be immunized against the oom killer if the value of its /proc//oomadj is set to the constant OOM_DISABLE (currently defined as -17 ).
操作方式上可以使用
echo -17 > /proc/$PID/oom_adj
更多可以参考这个网页( http://backdrift.org/oom-killer-how-to-create-oom-exclusions-in-linux )
,写一个定时任务,执行脚本,把当前进程的Pid加到这个oomadj里。
那怎么判断进程是不是被OOM Killer给干掉了呢?
可以从 /var/log/messages 这个文件里查找下,是否有之前pid对应的进程Kill信息,或者进程名,比如我们这里说的是Java应用,就直接查Java的就可以,像
这样的内容,
“Out of memory: Kill process 31201 (java) score 783 or sacrifice child
如果没有这个文件的权限,也可以直接使用如下命令
dmesg| egrep -i ‘killed process’
会有类似这样的输出
Killed process 13090 (java)
知道是被OOM Killer干掉的,那下一步就只能是保证环境的内存够用了,少被其它程序占用,加到受保护进程里,或者直接换个内存充足的服务器吧。 ^_^.
最后来看张图
(from: http://turnoff.us/geek/oom-killer/)
Reference
http://unix.stackexchange.com/questions/153585/how-the-oom-killer-decides-which-process-to-kill-first
http://backdrift.org/oom-killer-how-to-create-oom-exclusions-in-linux
http://stackoverflow.com/questions/10300883/tomcat-stopped-without-any-log-or-any-stack