记一次线上OOM Killer问题排查

2,177 阅读3分钟

前言

由于线上业务量激增,于是让运营新增了几台服务器加入集群。但是新加的机器总是在运行一段时间后,莫名down掉。

问题追踪

查看服务监控,发现每次宕机的时候都是业务高峰期,内存使用率高。怀疑是有内存泄露造成的OOM,于是查看线上日志,并未发现有相关OOM异常,而且日志每次都是打到一半突然没了,同时该情况只出现在新加的几台机器上面。简单分析后认为可能是业务高峰期内存占用过大,系统内存不足导致触发了OOM killer机制,将运行中的进程杀掉。

验证

  • 查看系统日志:dmesg -T或者查看如下目录日志/var/log/messages(模拟场景)

image.png

思考:如果是系统内存不足引起的OOM Killer,那应该所有高负载的机器都会宕机,为何当前只有新加的机器出现这种情况?

  • 查看系统配置free -m,以及java启动命令,发现机器内存大小为6G,并且未配置swap交换区,java启动命令设置-Xms-Xmx均为6G。

至此,问题已经水落石出。粗心的运维对于新增的机器并未采取一致的配置,堆得大小设置为机器的最大内存,却未配置交换区。非业务高峰期,堆虽然设置为6G,但linux并未真正为其分配了6G,所以不会出现任何异常。但是业务高峰期,随着内存使用量的增长,jvm会去申请更多内存代,此时linux会发现内存不足,于是就会触发OOM Killer。

扩展

虚拟内存分配与物理内存

当进程mmap申请一块内存时, Linux只是给它分配一个虚拟内存空间,只有等它实际使用该空间的时候,才会分配物理内存。所以有可能所有进程虚拟内存空间加起来 > 物理内存。一旦这些进程使用物理内存越来越多时,物理内存就不够用了。

此时我们可以开启swap,但是它也不能完全解决这个问题,只能缓解,因为swap分区也有一个总的容量。

所以我们需要根据不同的场景制定不同的虚拟内存使用策略,具体策略在/proc/sys/vm/overcommit_memory这个文件控制:

  • 值为0:虚拟内存控制策略就是大名鼎鼎的银行家算法,进程申请的虚拟空间,必须小于当前可用物理内存空间,才能申请通过。
  • 值为1:不做任何检查,所有虚拟内存申请都通过。
  • 值为2:不允许内存超量使用原则,所有进程的虚拟内存空间总和,不能超过物理内物理总量 (实际上还是要乘以一个小于1的因子,以保证内核态使用内存)

如果物理内存不足了,内核会怎么办

值为1和2时,就不用说了,虚拟内存总量一定会超过物理内存。值为2时,用户态不会超,但内核态会造成物理内存不足。如果物理内存不足,就会发生OOM(out-of-memory)行为。内核使用oom-killer模块去杀进程,释放内存,让当前系统可用。oom-killer会根据每进程使用的内存量和活跃做个综合评分,得分高者会被杀死,直到内存充足为止。当然,也会遇到无法释放足够的内存给当前系统使用,如果真发生这种情况,内核只能噗一声(panic),表示无力回天。