线上排查进程突然挂掉原因

1,863 阅读2分钟

对于线上应用,出现进程自动挂掉的原因,如果可以排除因程序本身原因,那么很大可能性是因为操作系统内存不够用,进程被操作系统kill掉了。

那如何确认是否是被操作系统kill掉的呢?

如果是因OutOfMemory被系统kill掉的进程,会在/var/log目录下的dmesg文件中留下最终的遗迹。可使用dmesg命令查看操作系统kill进程日记。

dmesg -T | grep -E -i -B100 'killed process'

命令行执行输出如下(go进程)。

......
Out of memory: Kill process 28670 (bfe) score 386 or sacrifice child
Killed process 28670, UID 555, (bfe) total-vm:8478620kB, anon-rss:6149940kB, file-rss:4kB

如果能知道挂掉的进程id,且在dmesg命令输出文本中找到,就能知道是否因内存原因被操作系统kill掉。

如果是虚拟机部署,建议在启动脚本中输出进程的id到文件存储,以便于后续问题排查。

此方法同样可以用于容器排查。

由于kubernetes的最小调度单元是Pod,如果只是容器重启,Pod不变,所在的物理机(虚拟机)就不变。而dmesg输出的是物理机(虚拟机)的操作系统kill进程日记,因此,虽然容器重启了,但我们还能使用dmesg命令查看进程被kill的原因。但需要注意,进程ID与容器内看到的进程ID是不同的。

一个容器部署的Java进程因内存原因被系统kill掉的案例分析。

截屏2022-03-28 上午10.18.19.png

表格部分字段说明(我们关心的字段):

  • pid:进程ID。
  • total-vm(total virtual memory):进程使用的总的虚拟内存,单位为4kB(内存页)。
  • rss(resident set size):驻留集大小,驻留集是指进程已装入内存的页面的集合,单位是内存页数,同样的每页4KB。

Killed process字段说明:

  • anon-rss(anonymous rss):匿名驻留集,比如malloc出来的就是匿名的。
  • file-rss:映射到设备和文件上的内存页面。

图中所示案例,进程35566的rss值是522668,乘以4kb/页,结果与anon-rss值2071208kb接近,差不多2G,而容器的内存限制就是2G,因此可以确定是因为内存原因被kill掉了。

这通常是因为我们给进程配置的jvm堆内存大于给容器分配的最大可用内存导致的,或者是java进程使用了堆外内存,堆内存+堆外内存大于给容器分配的最大可用内存导致的。