01月12, 2017

虚拟机莫名关机问题排查

最近发现有些虚拟机被莫名的关机,经过排查发现不是人为关机的,应该是系统触发的,最终发现是物理机内存用满触发了OOM-KILLER。

排查经过

先看物理机上log
alt
因为log记录的是格林尼治时间,加8小时是在16:06触发了关机操作。
我们查看一下/var/log/message,可以看到这样一条记录。
alt
系统发现内存不足,触发了OOM-KILLER,将此虚拟机进程kill了。 那么现在可以确认是OOM-KILLER把虚拟机关机了,那么OOM-KILLER是怎样的流程呢?

OOM-KILLER

因为操作系统对于内存的来讲分为虚拟内存和真实物理内存,理论上进程可以无限申请虚拟机内存,就是你在top上看到的VIRT,它并不代表进程已经使用了这些内存,top中的RES是进程真正使用的内存。
OOM-KILLER可以理解为kernel一种自我保护机制,内存使用满了,对所有进程都会有影响,所以它决定kill一些进程释放掉内存,来保证其它进程正常工作。
内核参数/proc/sys/vm/overcommit_memory,控制是否可以过量申请内存,默认是0

0:默认设置,内核执行启发式的过量使用处理

1:内核执行无内存的过量使用处理。使用这个值会增大内存超载的可能性

2:内存的使用量等于swap的大小+RAM*overcommit_ratio的值。如果希望减小内存的过度使用,这个值是最安全的

虚拟内存和真实内存之间有一张内存映射表,这里面的机制非常复杂,大内存还有多级映射关系,还有TLB缓冲等,这里不展开了。 因为这种虚拟内存分配机制,如果内存用光了,操作系统所有进程都挂了,所以操作系统有一个OOM-KILLER机制,通过一些机制kill,它认为可以kill的进程,达到缓解内存使用的目的。 控制参数

/proc/sys/vm/panic_on_oom #设置为1时,在OOM Killer运行时可以不发送进程信号,而是使内核产生重大故障。默认为0,就是kill 
/proc/sys/vm/min_free_kbytes #Linux 提供了这样一个参数min_free_kbytes,用来确定系统开始回收内存的阀值,控制系统的空闲内存。值越高,内核越早开始回收内存,空闲内存越高。
/proc/sys/vm/oom_kill_allocating_task #从Linux 2.6.24开始proc文件系统就有oom_kill_allocating_task。如果对此设置除0以外的值,则促使OOM Killer运行的进程自身将接收信号。此处省略对所有进程的得分计算过程。
/proc/sys/vm/oom_dump_tasks #从Linux 2.6.25开始,将oom_dump_tasks设置为除0以外的值时,在OOM Killer运行时的输出中会增加进程的列表信息。

新的内核去掉了oom-kill参数,所以如果想关闭oom-killer机制可以设置overcommit_memory=2

swap一定程度上可以缓解OOM的触发,当swap用满,内存没有地方可换出,将会触发OOM

oom-killer评分机制

大家知道了OOM-KILLER机制,内存用满了,要kill进程,但是kernel到底要kill哪些进程呢,是随机kill么?当然不是,这就涉及到oom-killer的评分机制。
首先有三个内核参数

oom_adj #淘汰
oom_score_adj #评分指数,-1000~1000,指数越小越不可能被kill
oom_score #进程评分,评分越高,越优先被kill

除了指数以外,oom-killer还通过一个公式来确定谁分数最大,大致就是“占用内存越高”,“使用时间越短”,分数越高 oom select_bad_process() 是负责找出当前系统里面最适合杀死的进程. 那么这个最适合杀死的进程的规则是怎样的呢 alt
可以看出这里选择的规则是需要vm 尽可能多的进程, 并且运行时间尽可能短的. 因为长时间运行的进程出概率的问题很小, 要出问题很早就出问题了. 因此出现oom 更大概率的可能是运行时间不长的进程。

由此其实可以反推出一种现象,一个进程被kill了,你把它再启动起来,再次OOM的时候,它还会被优先kill,造成恶性循环。

再次排查

知道了OOM-KILLER机制以后,我们再次缕一下虚拟机被关机的流程。
我们再次缕一下虚拟机被关机的流程。 在qemu的log里看到:16:06触发了关机操作。 在message log里看到,OOM被触发

Oct 17 16:06:44 kernel: qemu-kvm invoked oom-killer: gfp_mask=0x280da, order=0, oom_score_adj=0

oom-killer列出所有进程的内存和评分指数信息,开始评分
alt

我们也能看到,ssh等进程指数是非常低的,所有OOM时候不用但是ssh被kill了,而且root权限的进程默认提升3%指数。

进程13486被kill,它的评分是158,它使用了13G的虚拟机内存,7G多的真实内存。

Oct 17 16:06:44 kernel: Out of memory: Kill process 13486 (qemu-system-x86) score 158 or sacrifice child
Oct 17 16:06:44 kernel: Killed process 13486 (qemu-system-x86) total-vm:13664256kB, anon-rss:7258972kB, file-rss:4856kB

查看监控,在93G左右内存开始下降,因为min_free_kbytes到了阈值,触发了OOM-KILLER,下降到78G左右,释放了15G左右内存,和kill那两台虚拟机占用的内存数量相符。

总结

至此我们知道了,虚拟机被无故关机就是因为OOM-KILLER被触发了,那么得到的一些结论就是:

  1. 只有在内存被超卖的物理机上才会有此问题,所以内存最好不要被超卖。
  2. 物理机触发阈值都是90112,这是操作系统kernel设置的。
  3. oom-killer是操作系统的保护机制,我们不应该关闭它,适当的调大阈值,避免误杀

本文链接:https://www.opsdev.cn/post/vmshutdownissue.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。