这个问题通常由操作系统物理内存耗尽或应用运行的Java虚拟机进程Crash导致,本文以Linux操作系统为例说明如何解决。

操作系统物理内存耗尽,触发操作系统OOM Killer

当操作系统物理内存和交换空间不够用时,操作系统的OOM Killer机制(默认打开)就会选择性地杀死进程,那么它是怎样知道要先杀死哪个进程呢?其实Linux的每个进程都有一个oom_score(位于/proc/<pid>/oom_score),这个值越大,就越有可能被OOM Killer选中并杀死。

当一个进程被OOM Killer杀死以后会向操作系统日志写入杀死的进程PID等信息,所以判断进程是否被OOM Killer,就可以通过搜索操作系统日志来得知。

ECS集群进程被OOM Killer的日志:

[Wed Aug 31 16:36:42 2017] Out of memory: Kill process 43805 (keystone-all) score 249 or sacrifice child
            [Wed Aug 31 16:36:42 2017] Killed process 43805 (keystone-all) total-vm:4446352kB, anon-rss:4053140kB, file-rss:68kB
            [Wed Aug 31 16:56:25 2017] keystone-all invoked oom-killer: gfp_mask=0x280da, order=0, oom_score_adj=0
            [Wed Aug 31 16:56:25 2017] keystone-all cpuset=/ mems_allowed=0
            [Wed Aug 31 16:56:25 2017] CPU: 2 PID: 88196 Comm: keystone-all Not tainted 3.10.0-327.13.1.el7.x86_64 #1

Swarm集群进程被OOM Killer的日志:

Memory cgroup out of memory: Kill process 20911 (beam.smp) score 1001 or sacrifice child
Killed process 20977 (sh) total-vm:4404kB, anon-rss:0kB, file-rss:508kB

总结起来搜索命令为:

root# grep -i 'killed process' /var/log/messages

或者:

root# egrep "oom-killer|total-vm" /var/log/messages

遇到此问题时,解决办法有以下几个:

  • 增大ECS实例物理内存或者减少被杀死的进程分配的内存值。
  • 检查ECS实例是否挂载了Swap交换分区( ECS实例默认不挂载Swap交换分区 ),如果未挂载(阿里云ECS环境大多数OOM Killer的问题都因为未挂载Swap交换分区,相比性能,进程健康性更加重要)请搜索Linux挂载Swap交换分区的方法并自行挂载Swap交换分区。

应用运行的Java虚拟机进程Crash(异常退出)

Java虚拟机通常会由于异常的JNI调用、C Heap OOM、其他Bug等原因在运行时进程Crash,发生此问题时,会在当前JVM进程的工作目录(通过pwdx <jvm_pid>命令可查)生成一个hs_err_<jvm_pid>.log。通常,从这个日志文件中即可查到Java虚拟机Crash时执行的线程或原因(必要时需要通过允许生成coredump文件进一步分析)。

另外,在EDAS Console中可通过勾选应用基本信息页面的异常退出分析选项,配合应用监控告警功能,Java虚拟机进程退出时,就会发出告警,然后登录ECS实例查找相关日志,分析具体原因。

EDAS应用异常退出分析