MySQL OOM 系统二 OOM Killer |
本文标签:OOM,Killer 这里就涉及到一个问题,到底Kill掉谁呢?一般稍微了解一些Linux内核的同学第一反应是谁用的最多,就Kill掉谁 。这当然是Linux内核首先考虑的一种重要因素,但是也不完全是这样的,我们查一些Linux的内核方面的资料,可以知道其实Kill谁是由/proc/<pid>/oom_score来决定的,这个值每个进程一个,是由Linux内核的oom_badness()函数负责计算的 。那下面我们来仔细读一读badness()函数 。 在badness()函数的注释部分,写明了badness()函数的处理思路: 1) we lose the minimum amount of work done 总的来说就是Kill掉最小数量的进程来获取最大数量的内存,这与我们Kill掉占用内存最大的进程是吻合的 。 /* points = p->mm->total_vm; 分数的起始是进程实际使用的RAM内存,注意这里不包括SWAP,即OOM Killer只会与进程实际的物理内存有关,与Swap是没有关系的,并且我们可以看到,进程实际使用的物理内存越多,分数就越高,分数越高就越容易被牺牲掉 。 /* 这段表示子进程占用的内存都会计算到父进程上 。 s = int_sqrt(cpu_time); 这表明进程占用的CPU时间越长或者进程运行的时间越长,分数越低,越不容易被Kill掉 。 /* 如果进程优先级低(nice值,正值低优先级,负值高优先级),则Point翻倍 。 /* super用户的进程优先级较低 。 /* 直接可以访问原始设备的进程优先级较高 。 /* } 每个进程有个oomkilladj 可以设置该进程被kill的优先级,这个参数看上去对Point影响还是比较大的,oomkilladj 最大+15,最小是-17,越大越容易被干掉,这个值由于是移位运算,所以影响还是比较大的 。 下面我写个小程序实验一下: #define MEGABYTE 1024*1024*1024 #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc, char *argv[]) { void *myblock = NULL; myblock = (void *) malloc(MEGABYTE); printf("Currently allocating 1GB\n"); sleep(1); int count = 0; while( count < 10) { memset(myblock,1,100*1024*1024); myblock = myblock + 100*1024*1024; count++; printf("Currently allocating %d00 MB\n",count); sleep(10); } exit(0); } 上面的程序先申请一个1G的内存空间,然后100M为单位,填充这些内存空间 。在一个2G内存,400M Swap空间的机器上跑3个上面的进程 。我们看一下运行结果: test1、test2、test3分别申请了1G的虚拟内存空间(VIRT),然后每隔10s,实际占用的RAM空间就增长100M(RES) 。 当物理内存空间不足时,OS开始进行Swap,可用的Swap空间开始减少 。 当内存是在没有可分配的空间时,test1进程被操作系统Kill掉了 。dmesg 我们可以看到,test1进程被OS Kill掉,同时oom_score为1000 。 这3个进程的oom_adj全部都是默认值0 。下面我们来实验一下设置了oom_adj的效果 。重新启动3个进程,然后我们看到test2的PID是12640 我们运行一下下面的语句 echo 15 > /proc/12640/oom_adj 一段时间后,我们看到Swap空间急剧减少,基本上OS OOM_Killer要开动了 。 果然,不出意料,12640进程被kill掉了 。 所以为了避免自己需要的进程被kill掉,可以通过设置进程的oom_adj来实现 。当然,有的人会说,这一切都是超售引起的,既然Linux提供了overcommit_memory可以禁用overcommit特性,那为什么不禁用呢 。这有利也有弊,一旦禁用overcommit,就意味着MySQL根本无法申请超过实际内存的空间,而在MySQL中,存在很多动态申请内存空间的地方,如果申请不到,MySQL就会Crash,这大大增加了MySQL宕机的风险,这也是Linux为什么要overcommit的原因 。 有了上面的分析,我们不难看出,如果在不设置oom_adj的前提下,MySQL一般都会成为OOM_Killer的首选对象,因为MySQL一般都是内存的最大占用者 。那作为MySQL,我们如何尽量的去规避被Kill的风险呢,下一章我们将重点从MySQL的角度分析如何规避OOM 。 |