分享

我的oom-killer.doc

 犯错中成长 2013-07-06

Out of Memory 内存不够用的处理

  OOM是Out of Memory的简写,也就是内存不足。出现该问题的原因有很多,如程序内存泄漏等。内存泄漏问题可以通过定时地终止和重启有问题的程序来发现和解决。在比较新的Linux内核版本中,有一种名为OOM(Out Of Memory )杀手的算法,它可以在必要时执行Kill而杀掉一些程序。

oom-killer只考虑lowmemory而不考虑highmemory,即便这个时候物理内存还有很多free或者cached或者buffer,只要swap不足,便会执行oom-killer。
一、故障现象
服务器运行途中,客户端僵死,重新登录报网络连接失败;

远程登录服务器查看应用程序还在,而连接数据失败,数据库已经down掉。
(严重情况虽然可以ping通服务器地址,可进行屏幕输入,但已无法进行本地或远程登陆了。但是ssh死活连不了。原因是sshd进程被OOM killer干掉了。重启机器后查看系统日志会发现Out of Memory: Killed process ×××等只能强制重启。

二、故障分析
1、对于DB2而言,Instance Crash(实例崩溃)的原因不外乎产品defect(缺陷),堆栈越界,IO出错等。其实接触DB2时间长了,会发现相对来说,找到crash的原因比找到其他诸如hang问题的原因要容易很多。因为pd ,crash问题的套路是简单的。

首先看db2diag.log,通常搜索shutdown就能看到instance crash时刻的信息

分析日志:

2013-07-05-07.14.48.974682+480 E37187G508         LEVEL: Severe

PID     : 31006                TID  : 3019499200  PROC : db2gds

INSTANCE: db2inst1             NODE : 000

FUNCTION: DB2 UDB, oper system services, sqloEDUCodeTrapHandler, probe:10

MESSAGE : ADM0503C  An unexpected internal processing error has occurred.    

     发生了意外的内部错误处理

     ALL DB2 PROCESSES ASSOCIATED WITH THIS INSTANCE HAVE BEEN SHUTDOWN  所有与这个实例相关联的DB2进程已关机

     Diagnostic information has been recorded.                                       诊断信息已被记录

     Contact IBM Support for further assistance.                                     联系IBM支持进一步的援助

看看crash前的signal是不是11,如果是11,那十之八九,跟defect有关系了。如果是4,那多半是堆栈越界了。如果是9,那多半是人为或者HA等软件杀进程造成

2013-07-05-07.14.28.090821+480 I36367G390         LEVEL: Warning

PID     : 31049                TID  : 3019499200  PROC : db2logmgr (HDXTDB)

INSTANCE: db2inst1             NODE : 000

FUNCTION: DB2 UDB, data protection, sqlpgArchiveLogFile, probe:3180

MESSAGE : Successfully archived log file S0000354.LOG to VENDOR chain 0 from 

          /home/hdxtdb/db2inst1/NODE0000/SQL00001/SQLOGDIR/.

2013-07-05-07.14.46.741503+480 I36758G428         LEVEL: Severe

PID     : 31006                TID  : 3019499200  PROC : db2gds

INSTANCE: db2inst1             NODE : 000

FUNCTION: DB2 UDB, oper system services, sqloEDUSIGCHLDHandler, probe:50

DATA #1 : String, 157 bytes

Detected the death of an EDU with process id 31049

The signal number that terminated this process was 9

Look for trap files (t31049.*) in the dump directory

从日志看signal是9,人为杀死进程不会,软件最近在服务器只安装过第三方备份恢复软件,也没有杀死应用进程的。

2、查看系统日志

Jul  4 16:57:28 hdxt2 kernel: 23837: ERROR: cxfs_ioctl_create_stub(): Can't stub /mnt/hdxtdata/ImageFiles/20110106/201101069000100015000029B.jpg: It's already a stub

a、日志内显示一进程一秒钟读取 /mnt/hdxtdata/ImageFiles/20110106/ 885条数据,该目录存放大量图像文件目录不但容量大,而且都是小文件

可能在服务器做大量数据操作时,使内存过多造成内存不足,

继续观察系统日志,有如下的信息:
Jul  5 07:14:31 hdxt2 kernel: Free pages:    11472384kB (11458944kB HighMem)

Jul  5 07:14:31 hdxt2 kernel: Active:536620 inactive:550502 dirty:86527 writeback:0 unstable:0 free:2868096 slab:183361 mapped:140913 pagetables:10236

Jul  5 07:14:31 hdxt2 kernel: DMA free:12512kB min:16kB low:32kB high:48kB active:0kB inactive:0kB present:16384kB pages_scanned:1357 all_unreclaimable? yes

Jul  5 07:14:31 hdxt2 kernel: protections[]: 0 0 0

Jul  5 07:14:31 hdxt2 kernel: Normal free:928kB min:928kB low:1856kB high:2784kB active:2400kB inactive:1364kB present:901120kB pages_scanned:5973 all_unreclaimable? yes

Jul  5 07:14:31 hdxt2 kernel: protections[]: 0 0 0

Jul  5 07:14:31 hdxt2 kernel: HighMem free:11458944kB min:512kB low:1024kB high:1536kB active:2144080kB inactive:2200644kB present:16908288kB pages_scanned:0 all_unreclaimable? no

Jul  5 07:14:31 hdxt2 kernel: protections[]: 0 0 0

Jul  5 07:14:31 hdxt2 kernel: DMA: 2*4kB 1*8kB 3*16kB 3*32kB 3*64kB 3*128kB 2*256kB 0*512kB 1*1024kB 1*2048kB 2*4096kB = 12512kB

Jul  5 07:14:31 hdxt2 kernel: Normal: 0*4kB 108*8kB 4*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 928kB

Jul  5 07:14:31 hdxt2 kernel: HighMem: 0*4kB 0*8kB 0*16kB 0*32kB 0*64kB 17831*128kB 14004*256kB 6929*512kB 1682*1024kB 151*2048kB 3*4096kB = 11458944kB

Jul  5 07:14:31 hdxt2 kernel: Swap cache: add 14669739, delete 14668200, find 2819971/5158508, race 164+6007

Jul  5 07:14:31 hdxt2 kernel: 0 bounce buffer pages      0弹性缓冲区页

Jul  5 07:14:31 hdxt2 kernel: Free swap:       8377852kB  空闲(自由)交换

Jul  5 07:14:31 hdxt2 kernel: 4456448 pages of RAM       页的RAM

Jul  5 07:14:31 hdxt2 kernel: 3963728 pages of HIGHMEM   高内存页

Jul  5 07:14:31 hdxt2 kernel: 299737 reserved pages      保留页

Jul  5 07:14:31 hdxt2 kernel: 1760404 pages shared        共享页

Jul  5 07:14:31 hdxt2 kernel: 1761 pages swap cached      页面交换内存

Jul  5 07:14:31 hdxt2 kernel: Out of Memory: Killed process 31684 (CISSer).

Jul  5 07:14:46 hdxt2 kernel: oom-killer: gfp_mask=0xd0

Jul  5 07:14:46 hdxt2 kernel: Mem-info:

Jul  5 07:14:46 hdxt2 kernel: DMA per-cpu:

报错信息和屏幕显示一直,并且后续一直报相同信息
Jul  5 07:14:51 hdxt2 kernel: Out of Memory: Killed process 31049 (db2sysc).

Jul  5 07:14:55 hdxt2 kernel: Out of Memory: Killed process 31047 (db2sysc).
至此,能判断故障发生时,内核还处于可运行状态,通过日志还可以看到

b、Out of Memory明显内存不足,而服务器内存16G,

1从free看,可用物理内存很低,cached和buffers都比较低;
2swap使用率比较高,free swap很高,swap io交换比较频繁;
3死机前一段时间,一些进程会不明原因的死掉。

分析原因为内核驱动模块进程对大量小文件进行批量操作时,造成页面频繁换进换出缺少非活动页,触发了OOM killer机制,导致部分服务被强制终止而引发了问题。我们认为需要进行Memory性能调整:例如在使用vmstat命令时发现,memory的cache使用率非常低,而swap的si或者so则有比较高的数据值时,应该警惕内存的性能问题。

c、OOM Killer,一个保护机制,用于避免在内存不足的时候不至于出现严重问题,把一些无关的进程优先杀掉,即在内存严重不足时,系统为了继续运转,内核会挑选一个进程,将其杀掉,以释放内存,缓解内存不足情况,不过这种保护是有限的,不能完全的保护进程的运行。 在我的服务器中,1个16Gb内存的服务器,还是会被oom-killer杀死进程。事实证明,这个问题的原因是low memory耗尽在网上查询:内核使用low memory来跟踪所有的内存分配,这样的话一个16GB内存的系统比一个4GB内存的系统,需要消耗更多的low memory,可能有4倍之多。

有两种方法查看 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都会杀死进程,以保持系统的正常运行。

d、 首先确认该系统的版本是32位

#uname -a

Linux alarm 2.6.9-67.ELsmp #1 SMP Wed Nov 7 13:58:04 EST 2007 i686 i686 i386

我们了解一下32位Linux的内存管理结构在32位CPU下寻址范围是有限的,Linux内核定义了下面三个区域:

  # DMA: 0x00000000 -  0x00999999 (0 - 16 MB) 

  # LowMem: 0x01000000 - 0x037999999 (16 - 896 MB) - size: 880MB

  # HighMem: 0x038000000 - <硬件特定> 

LowMem 区 (也叫 NORMAL ZONE ) 一共 880 MB,而且不能改变(除非用 hugemem 内核)。对于高负载的系统,就可能因为 LowMem 利用不好而引发 OOM Killer 。一个可能原因是 LowFree 太少了,另外一个原因是 LowMem 里都是碎片,请求不到连续的内存区域(根据网上查询, 有些应用一次性请求比较大的内存,恰恰又是 880M 之内的,空闲的(LowFree)不够大,就会触发 OOM Killer)

 查看当前LowFree值: cat /proc/meminfo | grep LowFree

 查看LowMem内存碎片:cat /proc/buddyinfo

上面这命令需要在2.6内核才有效。

 查看当前LowFree值: cat /proc/meminfo | grep LowFree

 查看LowMem内存碎片:cat /proc/buddyinfo

上面这命令需要在2.6内核才有效。


三、故障处理
1、服务器启动后,可发现负载很高:并且内存消耗很快。
# uptime
12:33:17 up 1 day, 11:26,  1 user,  load average: 5.04, 90.02, 8.00

2、查看进程的内容
使用lsof和ps命令分析其工作内容:
观察发现,进程在运行一段时间后并没有退出,也没有切换到其他目录,怀疑已因工作量太大被卡死。
3、停止服务
停止第三方软件
服务被停止,但进程依旧存在,内存仍不断被消耗。只能终止相关进程:
lsof -p ****
ps -ef|grep ****
killall ****
命令运行成功后,系统负载恢复正常。
归档备份服务不能停,但重启服务内核驱动模块进程进程仍被卡死,问题依旧。

4、有如下方法可以解决该问题:

 a、升级到64位系统,这是最好的方法,因为此时所有的内存都属low memory,如此时提示out of memory,则真的是low memory耗尽,真的OOM了。

 b、如必须使用32位系统,那么可以使用hugemem内核,此时内核会以不同的方式分割low/high memory,而大多数情况下会提供足够多的low memory至high memory的映射,此时很简单的一个修复方法是可以安装hugemem内核包,然后重启。

  c、如果hugemem内核也用不了,那么我们可以尝试将/proc/sys/vm/lower_zone_protection的值设为250或更大,可使用如下命令查看和设置该值:cat /proc/sys/vm/lower_zone_protection

     echo 250 > /proc/sys/vm/lower_zone_protection

    或者可以修改/etc/sysctl.conf文件,以便重启后生效,添加的内容如下:

    vm.lower_zone_protection = 250

    d、实在没办法,那么我们把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"

    5、或者不把oom-killer关掉,只针对单一进程处理,把某个进程保护起来,此时,我们可以使用如下命令:

       echo -17 > /proc/[pid]/oom_adj

       /proc/[pid]/oom_adj中oom_adj的取值范围是-17~15,当该值为-17时,系统将不会杀死指定pid的进程,而-16~15则会使得进程的/proc/[pid]/oom_adj值呈指数(K*2^n)形式递增,即它们被杀掉的可能性呈指数递增。针对init(进程号为1)这个进程,无论该值设为多少都不会被杀。

四、总结
 一直以来该服务器数据库运行都是正常的,在进行图像数据归档和数据库归档备份时安装软件后,出现应用程序down掉,数据库down掉,甚至数据库无法成功启动。1个16G内存的服务器,在内核驱动模块执行时并且对数据库执行大数据执行时或者数据库归档备份时,造成low memory耗尽当low memory耗尽,不管high memory剩多少,oom-killer都会杀死进程(一般杀死占内存最大的进程),以保持系统的正常运行。所以把数据库进程杀掉,致使应用程序连不上数据库,而影响正常工作。 内核使用low memory来跟踪所有的内存分配,这样的话一个16GB内存的系统比一个4GB内存的系统,需要消耗更多的low memory,当low memory耗尽,即便系统仍然有剩余内存,仍然会触发oom-killer。在2.6内核的表现是,杀掉占用内存最高的进程,所以会导致数据库、sshd等进程被杀掉,造成系统无法登录。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多