如果线上出现了问题,如何在JVM运行时排查问题
首先查看应用运行情况
使用top 指令查看当前应用运行情况:
定位到 PID为27775 的进程占用CPU较高
接下来可以用
top -Hp <pid>
查看指定应用运行情况
这里的PID指的是PID为27775的进程创建的子进程。
定位到 28021 占用 CPU 异常高
printf 0x%x 28021
将此数字转换为十六进制数 0x6d75,然后使用jstack命令
jstack 27775 > stack.log
将 堆栈日志输出到statck.log
vim stack.log
搜索 0x6d75, 可以定位到该线程的堆栈情况
"pool-12-thread-2" Id=243 cpuUsage=79% RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
……………… 省略
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3008)
……………… 省略
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2486)
……………… 省略
at com.varena.tournament.consumer.task.MatchTask.resovleTimoutRollSelectionMatch(MatchTask.java:76)
运行时堆栈已经打印出来,可以看到此处有大量的 MySQL IO ,方法也定位到是 resovleTimoutRollSelectionMatch
到目前为止已经定位到了问题,就是这个方法导致的cpu占用高。
上面介绍的是不适用docker去部署项目可以这么排查。
实际上在执行 jstack 命令时, 会因为 docker 内使用的是 openjdk 镜像, 而本机使用的是
Oracle HotSpot VM 的不同, 导出 jstack 命令异常。
因为上述问题, 在实际操作中使用的是 Arthas 做的查看堆栈操作。
Arthas 使用方法 (前提是使用了我封装好的镜像, 此处还没有更新到全部 Jenkins 发布脚本中, 目前dev 在用)
docker ps 查出你的应用 container id
docker exec -it {container_id} /bin/sh -c "java -jar /opt/arthas/arthas-boot.jar"
thread 命令
-n 3 打印 cpu 占用率排名前 3 的线程堆栈
$ thread -n 3
"pool-12-thread-2" Id=243 cpuUsage=79% RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
……………… 省略
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3008)
……………… 省略
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2486)
……………… 省略
at com.varena.tournament.consumer.task.MatchTask.resovleTimoutRollSelectionMatch(MatchTask.java:76)
一样的玩法, 还是 top, top -p <pid>, H 查看 CPU 占用高的线程
注意日常观测应用的运行状态才能更好地优化应用性能。