godaddy 的vds上的一个OOM异常

一、概述

程序部署到godady(1G内存+10G硬盘+linux centos)上已经有一段时间了,最近没做任何改动的情况下发现tomcat老是莫名奇妙的宕掉。报如下异常

Java HotSpot(TM) Client VM warning: Exception java.lang.OutOfMemoryError occurred dispatching signal SIGTERM to handler- the VM may need to be forcibly terminated

二、处理思路

1、看是不是程序不够优化,是不是有内存泄露的地方

2、出动jprofile进行内存监控

三、初步结果

1、程序在本地跑的相当正常

2、内存貌似没泄露的地方

四、峰会路转

1、终于知道了godaddy竟然有oom-killer的机制,因为是虚拟机,当我们其他程序发现内存不够用的时候,godaddy的程序会启动linux的oom-killer机制,将占用内存最多的进程给kill了

2、发现godaddy的竟然没swap空间

3、引用老外的两篇文章:

http://blog.krecan.net/2008/03/24/help-someone-is-killing-my-tomcat/

http://blog.krecan.net/2008/03/26/tomcat-killer-demystified/

这老外出现的问题和我一样只是解释了oom-killer的机制

五、oom-killer机制

原文作者:Eric Sisler 

原文链接:http://www.redhat.com/archives/taroon-list/2007-August/msg00006.html

由于这个问题似乎在不同的邮件列表中出现,我已经将此消息张贴到红帽一般性讨论列表了,RHEL3(Taroon)和RHEL4(Nahant)列表。很抱歉我没有时间来更早的发布它。

通常,在大内存(6Gb+)服务器上,out of memory killer (oom-killer)也会杀死进程。在很多case中,人们都困惑地报告说还有剩余内存的情况下,为何oom-killer还会杀死进程?现象是在 /var/log/messages 日志中,有如下信息:

  Out of Memory: Killed process [PID] [process name].

在我自己的case中,我在VMware中升级了各个RHEL3到RHEL4,有1个16Gb内存的服务器,还是会被oom-killer杀死进程。不用说,这非常令人沮丧。

事实证明,这个问题的原因是low memory耗尽。 引用Tom的话“内核使用low memory来跟踪所有的内存分配,这样的话一个16GB内存的系统比一个4GB内存的系统,需要消耗更多的low memory,可能有4倍之多。这种额外的压力从你刚启动系统那一刻就开始存在了,因为内核结构必须为潜在的跟踪四倍多的内存分配而调整大小( The kernel uses low memory to track allocations of all memory thus a system with 16GB of memory will use significantly more low memory than a system with 4GB, perhaps as much as 4 times. This extra pressure happens from the moment you turn the system on before you do anything at all because the kernel structures have to be sized for the potential of tracking allocations in four times as much memory)”。

有两种方法查看 low memory 和 high memory 的状态:

# egrep 'High|Low' /proc/meminfo
HighTotal:     5111780 kB
HighFree:         1172 kB
LowTotal:       795688 kB
LowFree:         16788 kB

# free -lm
             total       used       free     shared    buffers     cached
Mem:          5769       5751         17          0          8       5267
Low:           777        760         16          0          0          0
High:         4991       4990          1          0          0          0
-/+ buffers/cache:        475       5293
Swap:         4773          0       4773
当low memory耗尽,不管high memory剩余多少,oom-killer都开始杀死进程,以保持系统的正常运转。

有两种方法解决这个问题:

1、如果可能,请升级到64位系统。

这是最好的解决办法,因为所有的内存都将成为low memory。如果你在这种情况下耗尽了low memory,那就真的是out of memory了。:-)

2、如果受限于必须使用32位系统,最好的解决办法是使用hugemem内核。

这种内核以不同的方式分割low/high memory,而且在大多数情况下会提供足够多的low memory到high memory的映射(This kernel splits low/high memory differently, and in most cases should provide enough low memory to map high memory)。在大多数案例中,这是一个很简单的修复方法:安装hugemem kernel RPM包,然后重启即可。

如果运行hugemem内核也不可能,你可以尝试将 /proc/sys/vm/lower_zone_protection 的值设置为250甚至更多。这将让内核愿意保护low memory,从而在分配内存时多考虑从high memory分配(This will cause the kernel to try to be more aggressive in defending the low zone from allocating memory that could potentially be allocated in the high memory zone.)。据我所知,此选项从2.6.x内核才开始可用。必要的是,您可能需要通过一些实验来找到您系统环境中最适合的值。可以使用下面方法快速的设 置和检查改值:

  # cat /proc/sys/vm/lower_zone_protection
  # echo "250" > /proc/sys/vm/lower_zone_protection
在 /etc/sysctl.conf 中加入设置,以便启动就生效:

  vm.lower_zone_protection = 250
作为最后的努力,你可以关闭oom-killer。这个选项可以导致系统挂起,所以请小心使用(风险自负)!

查看当前oom-killer的状态:

  # cat /proc/sys/vm/oom-kill
关闭/打开oom-killer:

  # echo "0" > /proc/sys/vm/oom-kill
  # echo "1" > /proc/sys/vm/oom-kill
加入到 /etc/sysctl.conf,以便启动就生效:

  vm.oom-kill = 0
当进程该被oom-killer杀死却没有被杀死时,相关信息会记录到 /var/log/messages:

  "Would have oom-killed but /proc/sys/vm/oom-kill is disabled"
很抱歉啰嗦多了。我希望它能帮助到那些正在被该问题困扰的人们。

–Eric


你可能感兴趣的:(godaddy)