前段时间有线上实例被负载均衡判定不可用,随即被摘除,同时我们收到该实例的 JVM GC 耗时较长的告警及负载较高的告警。从操作系统级别的监控可以看到磁盘读取速度几乎达到该规格的上限,近 120MB/s,IOPS 为 2200 左右,使用 ssh 登录该实例需要等待很久,且进入实例后几乎无法输入命令,2 核的机器负载达到了 20 左右。持续了七八分钟会恢复正常,恢复正常后我首先查看了 GC 日志,确认是否存在大量 FullGC,但是从日志中并未发现长时间的 Full GC,普通的 GC 的 real 耗时都很久,部分 GC 日志如下:
1 | 2021-12-29T13:35:04.683+0800: 401217.313: [GC pause (G1 Evacuation Pause) (young), 13.0059766 secs] |
可以看出 real 指标明显不正常,根据 REAL TIME IS GREATER THAN USER AND SYS TIME 及 Garbage-First Garbage Collector Tuning - Unusual System or Real-Time Usage 中的分析易知,该指标偏高主要有两种原因,一种是操作系统当前存在大量 IO 活动导致,一种是缺乏 CPU 周期导致。从操作系统级别的监控数据来看,CPU 利用率不及 50%,而磁盘读取及 IOPS 达到上限,故可初步确定是 IO 活动导致。
该实例未启用 SWAP 交换,在进程列表中也没看见 kswapd0,故排除了 SWAP 空间交换的可能。该实例被负载均衡摘除后还出现了两到三次 IO 被打满的情况,最后根据监控数据来看,是根据配置的容器失败策略进行了重启,释放了内存空间,此后再未出现 IO 高的问题。我在对应的实例上找到了 Linux OOM killer 的相关日志:
节点一:
1 | [Wed Dec 29 16:44:21 2021] java invoked oom-killer: gfp_mask=0x14200ca(GFP_HIGHUSER_MOVABLE), nodemask=(null), order=0, oom_score_adj=0 |
节点二:
1 | [Wed Dec 29 14:10:12 2021] dockerd invoked oom-killer: gfp_mask=0x14200ca(GFP_HIGHUSER_MOVABLE), nodemask=(null), order=0, oom_score_adj=-500 |
根据日志的时间,可以明确自 Java 进程重启后,应用恢复了正常,即释放了内存空间。在重启之前,内存在耗尽边缘时,猜测页面大量换入换出导致磁盘读取被打满,最后 Linux OOM killer 将 Java 进程结束,而此时 JVM 中并未发生 OOM,由于物理内存不足导致 Java 进行被操作系统结束,所以我们配置的 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/shared/heapdump.hprof
是不会自动生成 JVM 的堆转储的,也可以参考以下这两个链接:
- Generate memory dump when Java process is killed by OOM reaper - Stack Overflow
- HeapDumpOnOutOfMemoryError JVM option doesn’t s…| JBoss.org Content Archive (Read Only)
关于问题的原因初步估计还是应用存在内存泄漏导致,或者应用里存在大量对堆外内存的使用?等待下一次问题问题发生时拉取一次堆转储具体看看。我用 stress-ng
模拟内存压力大的场景可以复现该问题,表现一模一样,即磁盘读取和 IOPS 达到上限,命令行几乎无法操作,最后触发 Linux OOM killer 将 Java 进程结束,随后恢复正常。只是在之前的场景中是什么导致了内存压力大还需要问题复现后排查。
Reference
What do ‘real’, ‘user’ and ‘sys’ mean in the output of time(1)? - Stack Overflow
Eliminating Large JVM GC Pauses Caused by Background IO Traffic | LinkedIn Engineering
UNDERSTANDING G1 GC LOG FORMAT – GC easy – Universal Java GC Log Analyser
memory - High IO rate when the system out of RAM - Unix & Linux Stack Exchange
Troubleshooting High I/O Wait in Linux | Medium
testing - How to fill 90% of the free memory? - Unix & Linux Stack Exchange
Kernel/Reference/stress-ng - Ubuntu Wiki