JVM之监控工具

503 阅读6分钟

操作系统层面监控排查

CPU

1、通过top/vmstat找到目标进程的PID

%Cpu(s): 27.0 us,  9.4 sy,  0.0 ni, 59.0 id,  0.0 wa,  0.0 hi,  4.6 si,  0.0 st
KiB Mem :  7992404 total,  1195504 free,  4612256 used,  2184644 buff/cache
KiB Swap:  8388604 total,  8062456 free,   326148 used.  2837872 avail Mem 
PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
117466 cpicapp   20   0 8131068 3.064g  18420 S 147.7 40.2  15:28.31 java
100145 cpicapp   20   0 5022008 1.054g   8748 S   6.3 13.8   4404:40 java 

2、查看目标进程的CPU消耗命令:

pidstat -p PID -u 1 3

  • -p用于指定进程PID 

  • -u对CPU的监控 

  • 1 3 表述每秒采集一次,合计采集三次

    [XXXXXXX@Cloud System!! DT~]$pidstat -p 117466 -u 1 3

3、进一步监控目标进程的线程命令 :

pidstat -p PID 1 3 -u -t

[XXXXXXX@Cloud System!! DT~]$pidstat -p 117466 1 3 -u -t
Linux 3.10.0-862.3.2.el7.x86_64 (xncscbzcapp-c1e0p)     02/22/2021      _x86_64_        (4 CPU)

11:10:05 AM   UID      TGID       TID    %usr %system  %guest    %CPU   CPU  Command
11:10:06 AM  1050    117466         -  100.00   47.52    0.00  100.00     1  java
11:10:06 AM  1050         -    117466    0.00    0.00    0.00    0.00     1  |__java
11:10:06 AM  1050         -    117470    0.00    0.00    0.00    0.00     3  |__java
11:10:06 AM  1050         -    117471    0.00    0.00    0.00    0.00     0  |__java
11:10:06 AM  1050         -    117472    0.00    0.00    0.00    0.00     2  |__java
11:10:06 AM  1050         -    117473    0.00    0.00    0.00    0.00     3  |__java
11:10:06 AM  1050         -    117474    0.00    0.00    0.00    0.00     0  |__java
线程省略...
11:10:06 AM  1050         -    117555    6.93    1.98    0.00    8.91     0  |__java
11:10:06 AM  1050         -    117556    6.93    1.98    0.00    8.91     0  |__java
11:10:06 AM  1050         -    117557    4.95    1.98    0.00    6.93     1  |__java
11:10:06 AM  1050         -    117558    6.93    0.99    0.00    7.92     3  |__java
11:10:06 AM  1050         -    117568    0.00    0.00    0.00    0.00     2  |__java
11:10:06 AM  1050         -    117569    4.95    3.96    0.00    8.91     2  |__java
11:10:06 AM  1050         -    118167    5.94    0.99    0.00    6.93     1  |__java
11:10:06 AM  1050         -    118168    5.94    1.98    0.00    7.92     1  |__java
11:10:06 AM  1050         -    118169    4.95    0.99    0.00    5.94     2  |__java
11:10:06 AM  1050         -    118170    4.95    3.96    0.00    8.91     1  |__java
11:10:06 AM  1050         -    118171    4.95    2.97    0.00    7.92     0  |__java
11:10:06 AM  1050         -    118172    4.95    4.95    0.00    9.90     3  |__java
11:10:06 AM  1050         -    118173    3.96    3.96    0.00    7.92     0  |__java
11:10:06 AM  1050         -    118174    3.96    2.97    0.00    6.93     3  |__java
11:10:06 AM  1050         -    118175    4.95    3.96    0.00    8.91     0  |__java
11:10:06 AM  1050         -    118176    4.95    2.97    0.00    7.92     1  |__java

4、获得到高消耗线程ID之后执行 :

jstack -l PID >/cpic/thread_cpu.txt

然后查看thread.txt找到对应的线程ID分析即可,文件中的线程ID是十六进制的,使用时注意。

Full thread dump OpenJDK 64-Bit Server VM (17.920-b00 mixed mode):

"Attach Listener" #38 daemon prio=9 os_prio=0 tid=0x00007fd124004800 nid=0x1e84d waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"gatling-http-3-6" #37 prio=5 os_prio=0 tid=0x00007fd0f006f000 nid=0x1cda0 runnable [0x00007fd0e8198000]
   java.lang.Thread.State: RUNNABLE
        at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
        at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
        at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
        at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
        - locked <0x00000006f9d48dc8> (a io.netty.channel.nio.SelectedSelectionKeySet)
        - locked <0x00000006f9d49ec8> (a java.util.Collections$UnmodifiableSet)
        - locked <0x00000006f9d49df0> (a sun.nio.ch.EPollSelectorImpl)
        at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
        at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62)
        at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:757)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:412)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None
线程省略...
"gatling-http-3-8" #36 prio=5 os_prio=0 tid=0x00007fd0f4511800 nid=0x1cd9f runnable [0x00007fd0e8299000]
   java.lang.Thread.State: RUNNABLE
        at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
        at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
        at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
        at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
        - locked <0x00000006f9d354a0> (a io.netty.channel.nio.SelectedSelectionKeySet)
        - locked <0x00000006f9d365a0> (a java.util.Collections$UnmodifiableSet)
        - locked <0x00000006f9d364c8> (a sun.nio.ch.EPollSelectorImpl)
        at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
        at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62)
        at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:757)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:412)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

内存 

示例略,参考CPU部分

1、通过top/vmstat找到目标进程的PID ,查看目标进程的内存消耗 

2、通过PID查看进程中线程内存消耗 

3、pidstat -r -p PID 1 5 

4、jstack -l PID >/cpic/thread_memory.txt 

5、查看thread.txt找到对应的线程ID分析即可

IO 

示例略,参考CPU部分

1、通过PID查看进程中线程IO消耗 

2、pidstat -p PID -d -t 1 3 

3、jstack -l PID >/cpic/thread_memory.txt 

4、查看thread.txt找到对应的线程ID分析即可

网络 

查看网络状态:

  • netstat -an 

查看8080端口连接状况:

  • netstat -an | grep 80 

统计80端口连接数:

  • netst -nat | grep -i "80" | wc -l 

统计httpd协议连接数:

  • ps -ef | grep httpd | wc -l 

统计已连接上的,状态为"establish":

  • netstat -na | grep ESTABLISHED | wc -l

JVM层面监控排查

jstat

jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

option值:

  • -class 显示Classloder的相关信息 
  • -compiler 显示JIT编译的相关信息 -gc 显示与GC相关的堆信息 
  • -gccapacity 显示各个代的容量及使用情况 
  • -gccause 显示垃圾回收相关信息(同-gcutil),同时显示最后一次或者当前正在发生的垃圾回收的诱发原因 
  • -gcnew 显示新生代的相关信息 
  • -gcnewcapacity 显示新生代大小与使用情况 
  • -gcold 显示老年代和永久代的信息 
  • -gcoldcapacity 显示老生代大小 
  • -gcpermcapacity 显示永久代的大小 
  • -gcutil 显示垃圾回收信息 
  • -printcompliation 输出JIT编译的方法信息

示例:

jstat -gc PID 1000(每1000毫秒输出一次) 1000(一共输出1000次)

jmap

  • jmap -histo >filename.log java对象统计信息 
  • jmap -dump:live,format=b,file=filename.bin 堆快照
  • jmap -permstat 查看系统Classloader的信息 
  • jmap -finalizerinfo 查看系统finalzer队列中的对象

jstack

查看高消耗线程的另一种方式 :

  1. top查看消耗最高的JAVA进程 
  2. 使用top -Hp 来看这个进程里所有线程的cpu消耗情况 
  3. 使用printf "%x\n" 将进程号转换成16进制进程号 
  4. 使用jstack 查看线程栈,通过16进制进程号查找消耗高的线程

线程dump文件里,值得关注的线程状态有: 

  • 死锁,Deadlock(重点关注) 
  • 执行中,Runnable 
  • 等待资源,Waiting on condition(重点关注) 
  • 等待获取监视器,Waiting on monitor entry(重点关注) 
  • 暂停,Suspended 
  • 对象等待中,Object.wait() 或 TIMED_WAITING 
  • 阻塞,Blocked(重点关注) 
  • 停止,Parked

jcmd

  • jcmd GC.class_histogram 类的统计信息 
  • jcmd GC.heap_dump filename.dump 导出堆信息 
  • jcmd VM.sysytem_properties 获得系统的Properties内容 
  • jcmd VM.flags 获得启动参数 
  • jcmd PerfCounter.print 获得所有的PerData数据

JVM可视化分析工具

JVM参数设置优化 

一款开源的在线JVM参数设置调优工具: 

opts.console.perfma.com/

JVM-GC在线日志分析 

gceasy.io/

线程快照在线分析

thread.console.perfma.com/

堆快照分析

堆快照在线分析

memory.console.perfma.com/

Visual VM

JDK自带的jvisualvm.exe

MAT(MemoryAnalyzer)

下载地址:www.eclipse.org/mat/downloa…