1.现象描述
问题机器系统内存占用长时间90%以上,同时伴随着高iowait,在故障时无法ssh登录,同时也影响生产业务。但之后系统内存占用会突然掉下来,在内存自己掉下来后能ssh登录。
2.显示分析
2.1 sa日志分析
查看问题机器3月15日sa日志信息,首先来看问题发生时的系统内存使用情况。如下图所示,可以看到3月15日时系统内存基本已经耗尽,available经常在0K附近徘徊。
继续查看此时内存回收情况,如下图所示,可以看到此时系统的kswapd异步内存回收以及direct同步内存回收都已启用,但仍无法缓解系统内存紧张情况。结合上图的一个内存使用情况,大部分内存都为kbmemused,基本都是进程内存使用,无法被系统内存回收。
下一步查看问题发生时的系统CPU使用情况,如下图所示,可以看到问题发生时系统这边除了内存存在高占用情况,CPU也存在%iowait高,无空闲CPU资源的情况。
具体查看当时的磁盘使用情况,我们发现问题发生时存在大量的磁盘读现象,且磁盘读tps波动和CPU的%iowait波动情况一致,这说明当时CPU资源大都被大量的磁盘读取所使用。
综合上述我们可以看到在发生ssh无法登录、生产业务受影响时,系统的CPU、内存资源基本耗尽,且存在大量的磁盘读任务。
接下来我们来查看故障后的情况,如客户所说在问题发生后系统内存占用突然掉了下来,ssh等也恢复正常。对此我们同样查看sa日志,可以看到在长时间高内存占用后,系统内存使用率突然下降,同时磁盘读、CPU使用也同步降低。
系统内存、磁盘、cpu资源同步降低,这大概率是某些业务应用被终止了从而释放出了资源。对问题环境3月15日、重启后的3月19日以及正常机器3月19日的进程信息,我们发现问题环境3月15日系统资源使用率降低后的环境,java应用进程减少了4个,正常环境和重启后的问题机器都启动了5个java进程,但3月15日系统资源使用率降低后的环境中只剩下了1个。
2.2 问题环境java进程情况分析
如2.1节sa日志分析结果所示,导致问题环境内存、CPU资源基本耗尽的大概率是那几个java应用进程,且从sa日志的磁盘使用信息来看,这些业务进程当时应该在进行大量的磁盘读操作。
查看重启的问题环境机器,我们发现系统默认启动了5个java应用进程,从pstree来看,这些java进程都由同一脚本startserver.sh启动。
查看其进程启动参数,我们发现这些java进程是客户使用的自己编译的jdk1.7.0_67版本,而非麒麟这边的jdk。同时其设置了java进程初始堆内存和最大堆内存为2048M,永久代的最大内存为512MB。
考虑到其他java进程的堆外内存使用,这5个java进程最大可占用12.5G内存以上。再加上其他进程内存占用及各类缓存,在系统总内存为16G的情况下,遇到业务高峰,内存被耗尽是正常现象。如问题环境重启后的的sosreport日志所示,当前系统剩余内存仅剩余35M左右,available为1.8G。后续若是应用内存继续增长、再伴随大量磁盘读业务,很容易再次出现系统资源耗尽,无法ssh、业务受到影响的情况。
2.3 java进程内存使用分析
2.2节中,我们分析认为当前系统内存大小和java进程设置的最大内存使用上限及进程数量不太符合。但除了问题环境外,还有使用同样配置的其他机器未出现问题。对比两边java进程的内存使用情况后我们发现,二者java进程的虚拟内存申请大小基本一致,每个java进程基本都为7G左右,但实际的RSS却有不同,问题环境的java进程现在每个RSS基本为2-2.5G。
而正常环境java进程的RSS基本为1.4-1.6G,这大概率是导致两个环境系统资源使用不同的原因。
3.处理总结
综上所述,通过分析sa日志,我们可知问题环境15号ssh无法登录、业务受到影响的原因为系统内存、CPU资源基本耗尽,同时存在大量的磁盘读业务。对比多个sosreport文件信息后,我们能大致确定15号后续系统内存使用了降低、ssh恢复正常是由于5个java业务进程中4个挂掉了,从而释放了大量空闲内存,降低了磁盘读,缓解了CPU压力。
之后我们通过查看java进程的启动参数,我们发现在当前系统总可用内存不到16G的情况下,单个java进程初始堆内存和最大堆内存为2048M,永久代的最大内存为512MB。考虑到其他java进程的堆外内存使用,这5个java进程最大可占用12.5G内存以上。再加上其他进程内存占用及各类缓存,遇到业务高峰,内存被耗尽是正常现象。对此需要应用方评估java进程的内存使用负载与系统总内存是否匹配。
最后通过对比问题环境和正常环境的java进程内存情况,我们发现在二者java进程虚拟内存基本一致的情况下,问题环境java进程的RSS要明显高出不少。由于当前java进程使用的jdk为客户自己编译的jdk1.7.0_67版本,且实际的java应用内存使用基准、收到业务压力影响等因素均未可知,建议业务组自行对java进程内存使用进行分析。