Java 性能调优并诊断性能问题(jconsole,jvisualvm)

在某次工作的环境中发生接口调用一段时间之后出现 gateway timeout 504 问题,并随着大量的请求数量增大导致所有的接口都无法进行访问,第一时间怀疑是 tomcat 的请求连接数或线程池被压满,后来利用本篇提到的方法进行跟踪发现了问题;所以记录了如何使用 JVM 调优工具对这个问题进行定位并有效分析之后进行解决。

初步查看(基于 Linux 系统)

  • 利用 top 查看 进程ID;
  • 利用 top -Hp 进程ID 查看线程数;
  • 利用 pstack 进程ID 查看线程堆栈等信息。

JVM 配置变量

配置以下 JVM 参数变量方便远程客户端工具进行监控。

1
2
3
4
5
6
-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.port=6001
-Dcom.sun.management.jmxremote.rmi.port=6001
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=172.16.1.10

注意:如果 java 程序跑在容器服务中(如:docker),则配置的端口号必须为 6001 ,否则将无法正常利用客户端工具进连接。

打开 jvisualvm 工具

我使用的是 Mac 电脑,所以对应的 JDK 目录及工具在 /Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/bin 之中,直接打开 jvisualvm 输入 IP 地址与端口号即可。

IMAGE

图中右下角状态说明。

  • Running 线程正在运行;
  • Sleeping 线程睡眠中,也就是 Waiting;
  • Wait 线程等待中;
  • Park 线程等待中;
  • Monitor 阻塞状态,等待获取对象锁。

解决过程

打开调优工具之后,然后可以把服务进行重启,然后再查看目前 tomcat 所分配的线程数量(线程名格式:http-nio-8080-exec-1),然后再手动调用接口或程序来进行跟踪线程数量来查找问题进行解决;在大量的刷新接口之后,明显发现线程数进行大量的增加,然后我们点击右边的 Thread Dump 按钮把堆栈信息打印出来,下面两种图是随便挑选的两个堆栈信息,从而方便问题的分析。

图一

IMAGE

图二

IMAGE

结论

最后我们发现问题原来出现在连接池上面,导致大量的线程阻塞在获取连接处进行排队等待,所以我们加大了连接池的量最终解决了问题。