【开发笔记】茶余饭后:2、Java问题排查(压力测试性能监控)

       Java性能问题监控排查,主要就是对Java线程的堆栈进行分析,这就用到了Thread Dump工具,就是打印出Java应用运行时的堆栈信息来定位执行步骤中出现的问题。

【记压力测试关闭其他因素:1、修改java应用的日志等级;2、必要时关闭日志输出;3、数据库(中间件)等产品的日志输出;4、数据库连接池配置(以测试CPU核心数*2为界点);5、索引优化,oracle可以用pl/sql查看执行计划,mysql可以看慢查询以及explain查看执行计划等】

一、记录几个工具及命令

1、jvisualvm,jdk内置的性能分析工具。位置在jdk的安装目录的bin下面,可视化工具。(比较推荐!)

2、jstack,jdk内置的堆栈跟踪工具。jstack <pid> > <file>

3、jstat,jdk内置的JVM检测统计工具。jstat -gcutil <pid> 2000 10

4、jmap,jdk内置的内存映射工具,查看内存分布情况。jmap -histo <pid>

5、top,查看cpu和内存占用情况,top -H -p <pid>

6、linux服务器系统信息查看https://blog.csdn.net/u011636440/article/details/78611838

二、使用步骤以及描述

1、jvisualvm

详情收藏http://www.51testing.com/html/38/n-3724238.html

根据自身实践情况,主要几个步骤:

no.1 在服务器上需要监控的应用中添加启动参数如下:(使用工具的jdk版本一定要和监控的应用的jdk版本一致)

JAVA_OPTS="-Dcom.sun.management.jmxremote.port=1099 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false"

启动完成之后先用telnet ip port 测试一下连通性

no.2 打开jvisualvm.exe 建立监控连接

no.3 远程连接到服务器,图中右击后选择JMX连接

no.4 成功连接并监控到Java进程的运行信息

no.5 获取主要信息进行分析,首先打开监视界面,会得到下面4块图形,我主要监控着上面两个,一个是CPU的使用情况和对内存的占用情况,在查看CPU的使用情况的时候,可以查看到平均1核的CPU使用率,对于压测来说,希望应用能压到90%的使用率,再分析性能。而对内存则主要看垃圾回收的频率以及是否内存溢出。

no.6 其次主要看了抽样器,顺便说一下,查看线程可以看线程的运行时间,又可能一个线程一直运行,而其他线程都一直等待,这样的情况可能某一处引起了锁等待,只要每个线程的时间片分配不平均的话,就需要查看具体线程dump信息了。

抽样器感觉很不错,可以监控到应用的哪个方法用了多长时间,可以针对性的去查找dump文件中次堆栈情况,比如

根据上面的图,可以看到上面的几个方法占用时间很久,浪费了很多的时间,将这几个方法记下来之后,去dump文件中查看这几个方法的堆栈位置。

no.7 生成线程dump

点击图中的线程dump,可以生成threaddump文件,也可以在x线程下面看运行时间比较久的线程,记住线程号,从下面的dump文件中查找时间过长的方法和线程:(根据RUNNABLE查找)

通过堆栈位置的查找可以定位到问题代码,并进行纠正。这个主要可以在代码级去避免不必要的影响性能的code。下面进行DUMP分析。

通过这样的方式,在此次的压力测试中发现有两处写文件时间占用久和数据库id生成等待比较久,定位问题之后,发现一个是日志打印(将日志级别调高),一个是应用中报文写文件的操作(之间去除这样的操作,因为不是必要的)。数据库生成序列的时候还有待优化。

2、jstack

不仅可以通过工具获取dump文件,在服务器上也可以通过命令实现,jstack是一种,我在jstack的时候出现Unable to open socket file: target process not responding or HotSpot VM not这样错误,网上解决无果,就用kill -3 Java进程号也可以生成,生成的文件就是在项目的/logs/xxx.out文件中,要翻到最下面,而且要多kill -3几次,还要等一会。

dump 文件里,需要关注的线程状态有:

  1. 死锁,Deadlock,死锁线程,一般指多个线程调用期间进入了相互资源占用,导致一直等待无法释放的情况。
  2. 执行中,Runnable ,一般指该线程正在执行状态中,该线程占用了资源,正在处理某个操作。
  3. 等待资源,Waiting on condition,线程正处于等待资源或等待某个条件的发生。
  4. 等待获取监视器,Waiting on monitor entry,Moniter 是Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者class的锁,每个对象都有,也仅有一个 Monitor。
  5. 暂停,Suspended
  6. 对象等待中,Object.wait() 或 TIMED_WAITING,线程正处于等待资源或等待某个条件的发生。
  7. 阻塞,Blocked(重点关注)  ,线程正处于阻塞状态,指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。
  8. 停止,Parked

根据实际内容进行分析

"resin-22129" daemon prio=10 tid=0x00007fbe5c34e000 nid=0x4cb1 waiting on condition [0x00007fbe4ff7c000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:315)
    at com.caucho.env.thread2.ResinThread2.park(ResinThread2.java:196)
    at com.caucho.env.thread2.ResinThread2.runTasks(ResinThread2.java:147)
    at com.caucho.env.thread2.ResinThread2.run(ResinThread2.java:118)


"Timer-20" daemon prio=10 tid=0x00007fe3a4bfb800 nid=0x1a31 in Object.wait() [0x00007fe3a077a000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000006f0620ff0> (a java.util.TaskQueue)
    at java.util.TimerThread.mainLoop(Timer.java:552)
    - locked <0x00000006f0620ff0> (a java.util.TaskQueue)
    at java.util.TimerThread.run(Timer.java:505)

以上依次是:

  • "resin-22129" 线程名称:如果使用 java.lang.Thread 类生成一个线程的时候,线程名称为 Thread-(数字) 的形式,这里是resin生成的线程;
  • daemon 线程类型:线程分为守护线程 (daemon) 和非守护线程 (non-daemon) 两种,通常都是守护线程;
  • prio=10 线程优先级:默认为5,数字越大优先级越高;
  • tid=0x00007fbe5c34e000 JVM线程的id:JVM内部线程的唯一标识,通过 java.lang.Thread.getId()获取,通常用自增的方式实现;
  • nid=0x4cb1 系统线程id:对应的系统线程id(Native Thread ID),可以通过 top 命令进行查看,现场id是十六进制的形式;
  • waiting on condition 系统线程状态:这里是系统的线程状态,具体的含义见下面 系统线程状态 部分;
  • [0x00007fbe4ff7c000] 起始栈地址:线程堆栈调用的其实内存地址;
  • java.lang.Thread.State: WAITING (parking) JVM线程状态:这里标明了线程在代码级别的状态,详细的内容见下面的 JVM线程运行状态 部分。
  • 线程调用栈信息:下面就是当前线程调用的详细栈信息,用于代码的分析。堆栈信息应该从下向上解读,因为程序调用的顺序是从下向上的。

3、jstat待补充

4、jmap待补充

5、top

top命令可以查看当前系统运行的进程,以及cpu、内存等占用情况,主要是通过top找到Java进程

然后通过top -H -p4932 查看Java进程下线程的情况。

最后通过占用率比较高的线程号去dump文件中对应的堆栈信息,在定位问题。

三、linux常用命令整理

1、tail

主要就是tail -300f xx.log 查看实时日志,打印最新300条信息;

2、grep

管道,用法很多,经常用的就是ps -ef | grep -I 内容,grep 'xxx' /opt/.. > xx.log 将文件中包含xxx信息的内容打印到xx.log中

grep forest f.txt     #文件查找
grep forest f.txt cpf.txt #多文件查找
grep 'log' /home/admin -r -n #目录下查找所有符合关键字的文件
cat f.txt | grep -i shopbase    
grep 'shopbase' /home/admin -r -n --include *.{vm,java} #指定文件后缀
grep 'shopbase' /home/admin -r -n --exclude *.{vm,java} #反匹配
seq 10 | grep 5 -A 3    #上匹配
seq 10 | grep 5 -B 3    #下匹配
seq 10 | grep 5 -C 3    #上下匹配,平时用这个就妥了
cat f.txt | grep -c 'SHOPBASE'

3、find

常用作查找文件

find / -type f -size +1024M 在目录下查找文件大于1G的文件

find / -name xxx  在目录下查找名为xxx的文件

find . -type d(当前目录下的所有子目录)

find . -iname \*.txt(大小写都匹配)

4、df

df -h 查看磁盘占用情况

5、netstat -nat | grep -iw "port" | -wc -l

查看端口连接数,暂时发现性能越好,连接数越高,cpu占用率也越高

 

参考资源:

https://yq.aliyun.com/articles/652400?spm=a2c4e.11153940.blogcont69520.41.6a5cbec3geytas

https://yq.aliyun.com/articles/69520?utm_content=m_10360

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值