系统在运行的过程中往往会出现一些意想不到的问题,例如
- 响应时长突然升高,甚至应用无响应
- 内存使用量突然变大,甚至内存溢出
- CPU使用率持续增高
- JVM进程消失
面对这些问题,我们往往都需要通过以下的数据来进行分析
- 链路追踪,主要用于识别出各接口或方法的耗时情况
- Java Core数据,主要用于分析线程的运行情况
- Heap Dump转存,主要用于分析JVM内存的使用情况
- GC日志,主要分析GC的情况
- 数据库执行SQL耗时,主要分析慢SQL
场景1:JVM进程消失
导致JVM进程消失的一般情况有
- linux的OOM killer
- JVM自身故障
- JVM的OOM
linux的OOM killer
Linux 内核有个机制叫OOM killer(Out-Of-Memory killer),该机制会监控那些占用内存过大,尤其是瞬间很快消耗大量内存的进程,为了防止内存耗尽而内核会把该进程杀掉。 因此,你发现java进程突然没了,首先要怀疑是不是被linux的OOM killer给干掉了!
系统自身会将系统报错数据存储在以下文件中
/var/log/messages
可以通过以下命令来查询有关杀死进程的信息
egrep -i 'killed process' /var/log/messages
当然,你也可以去内核日志里头查询。有时Linux系统或者系统上运行的java或者其它进程,会发生一些莫名其妙的问题,比如突然挂掉了,比如突然重启等等。在软件上找不到问题所在,此时我们应该怀疑硬件或者内核的问题,此时我们就可以使用 dmesg来查看:
dmesg | grep java
例如以下的输出
[5673702.665338] Out of memory: Kill process 29953 (java) score 431 or sacrifice child
[5673702.665338] Killed process 29953, UID 500, (java) total-vm:9805316kB, anon-rss:2344496kB, file-rss:128kB
通过上面的输出可以看到内核对进程做的操作。
JVM自身故障
当JVM发生致命错误导致崩溃时,会生成一个hs_err_pid_xxx.log这样的文件,该文件包含了导致 JVM crash 的重要信息,我们可以通过分析该文件定位到导致 JVM Crash 的原因,从而修复保证系统稳定。
默认情况下,该文件是生成在工作目录下的,当然也可以通过 JVM 参数指定生成路径:
-XX:ErrorFile=/var/log/hs_err_pid<pid>.log
如何分析该文件,可参考 JVM 致命错误日志(hs_err_pid.log)解读
JVM的OOM
这种情况往往是因为内存泄漏、代码不合理;或者并发量太大,任务本身会消耗较多内存;或者就是内存配置太小而导致内存溢出。
可以通过添加以下参数来获取内存时的转存文件,然后对文件分析找出问题的代码
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=*/java.hprof;
场景2:无法提供响应
该场景包含两种情况,一种是新的请求被拒绝了,第二种是响应时长很大。有可能是服务的线程被使用完了,而导致使用完的原因可能有
- 线程的死锁
- 线程间进行资源竞争时长期等待资源响应
- JVM不断的full gc
这时可以抓取Java Core文件进行分析,通过下面的方式可以获取该文件
1、通过Java JDK自带的工具
jstack [-F] [-l] [-m] <pid>
参数说明:
选项 | 作用 |
-F | 当正常输出的请求不被响应时,强制输出线程堆栈 |
-m | 如果调用到本地方法的话,可以显示C/C++的堆栈 |
-l | 除堆栈外,显示关于锁的附加信息,在发生死锁时可以用jstack -l pid来观察锁持有情况 |
例如,将进程号为17246的线程转储输出到文件中
jstack -l 17264 > /tmp/threaddump.txt
至于怎么得到进程ID号,可通过linux的ps命令或jdk中的jps工具。
注意:应该在启动进程的所在用户下执行;同时,如果服务器上安装的是JRE而非JDK,那么将不能使用 jstack 工具获取thread dump文件
2、通过Unix/Linux的kill指令
如果服务器上只安装了JRE,那么可以通过kill命令来获取thread dump文件。
kill -3 <pid>
通过上面指令可以将thread dump信息打印到标准输出中。
同时,通过在Java命令中加上以下参数后可将thread dump输出到文件中。
-XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=~/jvm.log
- 你可以通过-XX:+LogVMOutput开启,或者-XX:-LogVMOutput关闭
- LogVMOutput必须配合参数-XX:+UnlockDiagnosticVMOptions使用,并且只能加在其后才能生效
场景3:CPU过高
这种情况依旧需要通过Thread Dump文件来分析,其操作过程大致如下
- top, 通过top命令找出cpu消耗大的java进程,并得到PID
- top -Hp pid,通过该命令查看制定进程下各个线程的cpu使用情况
- jstack -l [PID] >/tmp/log.txt , 抓取进程的dump文件
- 分析堆栈信息,将线程的ID转换成十六进制后再thread dump文件中查找
可参考文章:Java程序员必备:jstack命令解析
附:其他可参考文章
标签:文件,系统,排查,XX,线程,内存,JVM,进程,思路 From: https://blog.51cto.com/dengshuangfu/9072075