由于近期Xenserver系统的OOMkill引起的批量虚拟机hang死以及刀片宕机重启问题,所以针对Out of memory 问题进行了了解和熟悉。
根据查阅网上一些文档LINUX系统具有OOMKiller的保护机制,用于避免 Linux 在内存不足的时候不至于出太严重的问题,把一些无关紧要的进程杀掉,以保证系统的正常运行。
内存是通过指针寻址的,因而CPU的字长决定了CPU所能管理的地址空间的大小,该地址空间就被称为虚拟地址空间,因此32位CPU的虚拟地址空间大小是2的32次方=4 294 967 296为4G,这和实际的物理内存数量无关。
Linux内核将虚拟地址空间分成了两部分:
一部分是用户进程可用的,这部分地址是地址空间的低地址部分,从0到TASK_SIZE,称为用户空间;
一部分是由内核保留使用的,这部分地址是地址空间的高地址部分,从KERNELBASE到结束,称为内核空间;
所以在32位系统,一个进程的可寻址范围是有限的
Linux内核定义了下面三个区域:
# DMA: 0x00000000 - 0x00999999 (0 - 16 MB)
# LowMem: 0x01000000 - 0x037999999 (16 -896 MB) - size: 880MB
# HighMem: 0x038000000 - <硬件特定>
其中LowMem 区 (也叫 NORMALZONE ) 一共 880 MB,而且不能改变(除非用 hugemem 内核)。对于高负载的系统,就可能因为 LowMem 利用不好而引发 OOM Killer 。一个可能原因是 LowFree 太少了,另外一个原因是 LowMem 里都是碎片,请求不到连续的内存区域
检查当前 LowFree 的值:
# cat /proc/meminfo |grep LowFree
检查LowMem内存碎片:
# cat /proc/buddyinfo
上面这条命令要在 2.6 Kernel 环境下有效。
有如下方法可以解决该问题:
1.升级到64位系统,这是最好的方法,因为此时内核的寻址范围为2的64次方,所有内存都属low memory,如此时提示out of memory,则真的是low memory耗尽了。(目前云桌面xenserver位linux32位SMP内核2.6.32.12-0.7.1版本)
2. 如必须使用32位系统,那么可以使用hugemem内核,此时内核会以不同的方式分割low/high memory,而大多数情况下会提供足够多的low memory至high memory的映射,此时很简单的一个修复方法是可以安装hugemem内核包,然后重启。
备注:RedHat建议当物理内存在16GB之内,用SMP” kernel,在16GB-64GB之间使用”Hugemem” kernel.这是因为虚拟地址空间里有1G用于内核空间,而3G用于用户空间。而关健的一些数据结构是存放在1G内核空间的,在管理32G内存当中,需要用到0.5G来用于管理这些物理内存(容易触发OOM killer).虽然32位OS下,内核和用户空间的比例都是1:3,但Hugemem打了一个补丁,使比例成为4G:4G,即使内核空间和用户空间相互独立,所以也会有性能上的损失,因为应用程序的运行,通常会有内核和用户空间的切换。所以如果内存大于16G,建议使用64位的OS。
3.如果hugemem内核也用不了,那么我们可以尝试将/proc/sys/vm/lower_zone_protection的值设为250或更大,可使用如下命令查看和设置该值:
cat /proc/sys/vm/lower_zone_protection
echo250 > /proc/sys/vm/lower_zone_protection
或者可以修改/etc/sysctl.conf文件,以便重启后生效,添加的内容如下:
vm.lower_zone_protection= 250
备注:RHEL 4 ,新增了一个参数: vm.lower_zone_protection 。这个参数默认的单位为 MB,默认 0 的时候,LowMem 为 16MB。建议设置vm.lower_zone_protection = 200 甚至更大以避免 LowMem 区域的碎片,能解决这个问题 (这参数就是解决这个问题出来的)。
4.实在没办法,那么我们把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文件中,信息如下:
"Wouldhave 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)这个进程,无论该值设为多少都不会被杀。
6.另外打ctx xenserver024和0332个补丁也或可避免该OOMkill问题的出现。