一、系统性能监控
linux操作系统中有很多命令可以查看应用程序的性能情况,下面介绍一下这些常用的命令:
uptime:
可以查看的信息有系统时间,运行时间,连接数-其中每一个终端算一个连接,1,5,15分钟内的系统平均负载,也就是运行队列中的平均进程数。这是一个操作系统级的命令,可以查看当前操作系统的整体的状况如何。
top:常用的系统性能监控命令,可显示当前进程的cpu利用率和内存使用率,找到cpu利用率过高的进程,从而可以进一步分析问题。
vmstat:可以统计系统的CPU,内存,swap,io等情况,可以查看系统的繁忙状态。
pidstat:可以细致观察进程。该命令并非系统自带的工具,需要单独安装。在Centos下的安装命令是yum install sysstat,该命令可以用来监控CPU,监控IO以及监控内存。该命令的使用格式如下:
pidstat -p 指定进程 –u 监控CPU 每秒采样 一共3次
[root@node1 mnt]# pidstat -p 6377 -u 1 3
Linux 3.10.0-693.el7.x86_64 (node1) 11/18/2019 _x86_64_ (2 CPU)
05:46:48 AM UID PID %usr %system %guest %CPU CPU Command
05:46:49 AM 997 6377 95.00 0.00 0.00 95.00 1 java
05:46:50 AM 997 6377 97.03 0.00 0.00 97.03 1 java
05:46:51 AM 997 6377 100.00 0.00 0.00 100.00 1 java
Average: 997 6377 97.34 0.00 0.00 97.34 - java
结果显示的是三条数据,每秒钟采样一次结果,-u的意思是只监控CPU,所以只显示了CPU使用的情况。
[root@node1 mnt]# pidstat -p 6377 -u 1 3 -t
Linux 3.10.0-693.el7.x86_64 (node1) 11/18/2019 _x86_64_ (2 CPU)
05:46:57 AM UID TGID TID %usr %system %guest %CPU CPU Command
05:46:58 AM 997 6377 - 97.03 0.99 0.00 98.02 1 java
05:46:58 AM 997 - 6377 0.00 0.00 0.00 0.00 1 |__java
05:46:58 AM 997 - 6410 0.00 0.00 0.00 0.00 1 |__java
05:46:58 AM 997 - 6411 0.99 0.00 0.00 0.99 0 |__java
05:46:58 AM 997 - 6412 3.96 0.00 0.00 3.96 0 |__java
...
05:46:58 AM 997 - 6556 0.00 0.00 0.00 0.00 1 |__java
05:46:58 AM 997 - 6557 0.00 0.00 0.00 0.00 1 |__java
...
05:46:58 AM 997 - 6587 92.08 0.00 0.00 92.08 0 |__java
在监控进程的命令后面加上参数-t,我们可以看到线程的明细信息,可以看到线程ID为6587的cpu使用率比较高,后面的CPU一列指的是使用的哪一个CPU,本利中一共有两个CPU,该线程运行在0号CPU上。
有时候我们不只要看CPU的使用情况,我们还需要看IO的占用情况,以查看系统的瓶颈是否在IO上,将-u替换成-t就可以查看IO的使用情况,下面是使用-d查看IO情况的例子:
[root@node1 mnt]# pidstat -p 6377 1 3 -d -t
Linux 3.10.0-693.el7.x86_64 (node1) 11/18/2019 _x86_64_ (2 CPU)
05:52:57 AM UID TGID TID kB_rd/s kB_wr/s kB_ccwr/s Command
05:52:58 AM 997 6377 - 0.00 8.00 0.00 java
05:52:58 AM 997 - 6377 0.00 0.00 0.00 |__java
...
05:52:58 AM 997 - 6585 0.00 0.00 0.00 |__java
05:52:58 AM 997 - 6587 0.00 8.00 0.00 |__java
05:52:58 AM 997 - 6588 0.00 0.00 0.00 |__java
...
可以看到线程6587在进行写操作,速度是8kb每秒,与上面监控到的CPU利用率高的线程是一致的,后续可以进一步查看该线程,看该线程在进行何种操作。
2.java自带的工具
在%JAVA_HOME%/bin目录下有一些以exe为结尾的可执行文件,如jps.exe,这些是java自带的监控工具,其具体的实现是在tools.jar里面,这些可执行文件主要封装了一下入口。
jps
列出java进程,类似于ps命令,参数-q可以指定要输出的进程ID,不输出类的短名称,参数-m可以用于输出传递给main函数的参数,参数-l可以输出main函数的完整路径,-v则可以显示传递给jvm的参数。jps后面跟不同的参数会显示不同的信息:
[root@node1 ~]# su hdfs
[hdfs@node1 root]$ jps
42393 Jps
7214 NameNode
7217 SecondaryNameNode
7220 DataNode
[hdfs@node1 root]$ jps -m
7214 NameNode
42412 Jps -m
7217 SecondaryNameNode
7220 DataNode
[hdfs@node1 root]$ jps -m -l
7214 org.apache.hadoop.hdfs.server.namenode.NameNode
7217 org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode
7220 org.apache.hadoop.hdfs.server.datanode.DataNode
42434 sun.tools.jps.Jps -m -l
[hdfs@node1 root]$ jps -m -l -v
42517 sun.tools.jps.Jps -m -l -v -Dapplication.home=/usr/java/jdk1.7.0_80 -Xms8m
...
jps看到的信息是和ps查看的信息是一致的,jps可以只查看java进程,比ps要更专注一些,对于查找java程序的问题更方便一些。
jinfo
可以用来查看正在运行的java应用程序的扩展参数,并且支持在运行时修改部分参数。
-flag <ParName>:打印指定jvm的参数值
-flag [+|-]<ParName>:设置指定jvm参数的布尔值
-flag <ParName>=<value>:设置指定jvm参数的值:
/*查看新生代对象晋升到老年代对象的最大年龄,该参数显示的对象被复制的次数*/
[hdfs@node1 root]$ jinfo -flag MaxTenuringThreshold 7214
-XX:MaxTenuringThreshold=6
/*显示是否打印GC详细信息*/
[hdfs@node1 root]$ jinfo -flag PrintGCDetails 7214
-XX:-PrintGCDetails
/*修改运行时参数,设置可以打印GC详细信息*/
[hdfs@node1 root]$ jinfo -flag +PrintGCDetails 7214
[hdfs@node1 root]$ jinfo -flag PrintGCDetails 7214
-XX:+PrintGCDetails
jmap
生成java应用程序的堆快照和对象的统计信息。
jmap -histo 7214 > /tmp/class_info.txt
[hdfs@node1 tmp]$ jmap -histo 7214 > /tmp/class_info.txt
num #instances #bytes class name
----------------------------------------------
1: 92532 12252192 <constMethodKlass>
2: 92532 11854816 <methodKlass>
3: 7112 9229816 <constantPoolKlass>
...
3646: 1 16 java.lang.reflect.Proxy$KeyFactory
3647: 1 16 sun.reflect.GeneratedMethodAccessor197
Total 509627 65084496
类的统计信息是按实例数进行排序的,排在第一位的实例有92532个,类的名称是constMethodKlass,大小有12m左右,通过该统计信息可以初步判断应用程序中是否有异常的类。
Dump堆信息
可以将内存中的堆信息保存到一个文件中,然后利用分析工具可以进行离线分析。
jmap -dump:format=b,file=/tmp/dump_info.hprof 7214
jstack
打印线程信息,-l打印锁信息,-m打印java和native的帧信息,有时候jstack会没有响应,可以使用-F强制dump线程信息。
[hdfs@node1 tmp]$ jstack 7214 >> stack_info.txt
....
"main" prio=10 tid=0x00007f2158019800 nid=0x1d22 in Object.wait() [0x00007f215ef64000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000f8e27c68> (a org.apache.hadoop.ipc.ProtobufRpcEngine$Server)
at java.lang.Object.wait(Object.java:503)
at org.apache.hadoop.ipc.Server.join(Server.java:2705)
- locked <0x00000000f8e27c68> (a org.apache.hadoop.ipc.ProtobufRpcEngine$Server)
at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.join(NameNodeRpcServer.java:458)
at org.apache.hadoop.hdfs.server.namenode.NameNode.join(NameNode.java:890)
at org.apache.hadoop.hdfs.server.namenode.NameNode.main(NameNode.java:1617)
....
上面显示了main函数所在的线程的信息,其中tid是在jvm中的id,nid是在操作系统总的id。使用命令top -H -p 7214可以查看进程7214的线程信息,其中pid=7458就是main函数对应的线程信息。可以根据这个找到异常的进程所对应的函数,进而查找定位出问题的地方。
JConsole
图形化的监控工具,可以用来查看java应用程序的运行概况,监控堆信息,永久区的使用情况,类加载情况以及线程的信息等。jconsole的启动文件是jconsole.exe
Visual VM
Visual VM是一个功能强大的多合一故障诊断和性能监控的可视化工具,基本上jconsole能实现的功能visual vm都有,还能显示更详细的信息。Visual VM的启动文件是jvisualvm.exe。visual VM可以dump堆的信息,可以比较方便的分析堆内容。
死锁
假设线程A持有资源S1,请求资源S2,线程B持有资源S2,请求资源S1,S1和S2资源都是线程独占的,也就是一旦这个资源被持有,其他线程就得等待,等另外一个线程释放该资源后才可以被其他线程持有。这种情况下,线程A等待线程B释放资源,同时线程B也在等待线程A释放资源,如果没有外来力量的干预,就会一直等待下去,这种情况就是死锁。
通过JStack可以找到线程的死锁,通过每个线程锁定和等待的对象ID就可以找到对应的死锁线程ID.