线上性能问题
线上性能问题无非是以下几种:
1.内存问题(oom,内存泄露)
2.CPU问题(load高)
3.I/O问题(磁盘io,net io)
性能分析命令&工具
系统级命令:
top:查看系统的cpu情况
free:查看系统的内存占用情况
vmstat:查看关于内核线程、虚拟内存、磁盘、陷阱和 CPU 活动的统计信息
iostat:查看CPU统计信息和整个系统、适配器、tty 设备、磁盘和 CD-ROM 的输入/输出统计信息
netstat:各种网络相关信息,如网络连接,路由表,接口状态
jdk常用命令:
Jps:查看Java进程
Jinfo:观察运行中的java程序的运行环境参数:参数包括Java System属性和JVM命令行参数
Jstatd:启动jvm监控服务。它是一个基于rmi的应用,向远程机器提供本机jvm应用程序的信息。默认端口1099
Jstack:查看java进程的stack信息
Jstat:jdk命令中比较重要,也是相当实用的一个命令,可以观察到classloader,compiler,gc相关信息
Jmap:观察运行中的jvm内存的占用情况
Jhat:是用来分析java堆的命令,可以将堆中的对象以html的形式显示出来,包括对象的数量,大小等等,并支持对象查询语言
图形化工具
JConsole:JDK自带的基于JMX内存监控分析工具,在jdk/bin目录下
Visual VM:第三方的监控分析工具。JDK5.0以后被集成到JDK中,在jdk/bin目录下。Visual VM比JConsole要好用,推荐使用。
JProfiler:第三方的集成工具。个人感觉比上面2个都好用,内存分析粒度更细。
GCLogViewer:GC log趋势分析工具,能够检测内存泄露及日志比较。
TDA(thread dump analysis):线程栈信息分析工具
MemoryAnalyzer:JVM内存分析工具,能够对给出内存分析报告
housemd-assembly:淘宝员工开源工具,能够追踪内存对象的详细信息
另外还有一些特定商业版的工具,如hp的hpjmeter,ibm的Troubleshooting
常见问题分析步骤
因为线上问题很多时候是阶段性的,所以要想找到问题的root cause,一定要保存好现场数据。譬如:业务常用的日志,top,jstack,jmap,gclog数据等。有了这些数据,我们才能更好更快地追查出问题的root cause.
内存问题
OOM(out of memory)
oom就是内存不足,jvm中内存不足有以下三种:
-
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread---没有足够的内存空间为该线程分配java栈解决办法:调整-Xss设置的值
-
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space---堆的内存占用已经达到-Xmx设置的最大值解决办法:调整-Xmx的值
-
Caused by: java.lang.OutOfMemoryError: PermGen space---方法区的内存占用已经达到-XX:MaxPermSize设置的最大值解决办法:调整-XX:MaxPermSize的值
StackOverflow
所有栈帧大小总和大于-Xss设置的值,Exception in thread "main" java.lang.StackOverflowError(注意和上面1的区别)
GC相关的
首先,说一下单次gc的时间。不同的服务标准是不一样,服务主要分为:数据计算型服务,请求响应型服务。数据计算型服务,根据不同数据量,不同的计算密度,gc时间是不同的;请求响应型服务,一般来说,ygc在100ms-200ms/次左右,10s间隔。而fgc在1s/次左右,间隔分钟级。
gc常见异常:
-
ygc或fgc时间太长---young区或old区太大
解决办法:根据业务适当调小点
-
ygc或fgc频率太高---young区或old区太小
解决办法:根据业务适当调大点
-
promotion failed---Minor GC时,survivor space放不下、对象只能放入旧生代,而此时旧生代也放不下造成的
解决办法:根据业务适当调整小 -XX:SurvivorRatio,默认值是8。或者在jvm参数中加入以下参数:
-XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:CMSFullGCsBeforeCompaction=1
|
-
concurrent mode failure---CMS GC的过程中同时有对象要放入旧生代,而此时旧生代空间不足造成的
解决办法:可以通过调整参数加大old区大小,上面参数同上要加上
内存泄露
内存泄露,很难觉察。需要不断的去观察gc的情况,然后dump 内存进行分析,才能定义为到哪一段代码有问题。
1.查看gc是否异常
2.jmap -dump:live,file=mem.map pid把内存dump下来
3.通过mat(memory analyzer)分析内存对象及调用链,发现无法回收的对象
4.通过house-md可以实时抓取无法回收的对象的相关操作。创建的操作是.<init>方法,超赞的工具。
CPU问题
load高
1.top命令看一下系统的资源是否紧张,主要看load average,%st和比较耗cpu的进程。
2.vmstat 1看一下process的r,b以及cpu的各个参数。r长期大于1说明负载比较高;如果us的占比比较高,说明应用程序是耗cpu。
3.iostat 1看一下avg-cpu中%iowait的值,它 CPU等待硬件I/O时,所占用CPU百分比。通过这个参数可以看出io操作会不会影响到cpu。
4.jps -lv看一下java应用程序
5.top -H -p pid看一下你的应用程序中的那些线程耗cpu。同时jstack -l pid抓下堆栈。
6.对照这进程内的耗cpu的线程和堆栈信息,可以看一下程序中的那一部分比较耗cpu。(因为抓站是瞬时的,需要多次抓取做统计)
另外,可以通过监控数据可以看到jetty的线程数,如果线程数太多,也会影响到cpu的load.
IO问题
io等待时间长
1.iostat 1 查看下 io的各项参数,看下是不是存在大量数据的读写或者读写等待(主要针对io操作)
2.如果发现上述问题,需要看下代码的那些地方进行大量数据的读写。
3.另外,针对net io,需要实时抓栈(jstack -l pid)看一下,在那些的网络io堵住了。
注意:cpu load高到底是程序的计算量大还是网络io造成的?我们需要实际问题实际分析。如果是计算量大,通过top -H -p pid能看到进程内存存在大量的耗cpu线程;如果是网络等待导致cpu load高,我们可以通iostat,vmstat数据可以综合分析下。如果vmstat的r比较少,而iostat 的cpu %iowait比较高,说网络id存在瓶颈。
另外:具体的工具使用方法及状态参数说明如下:
ps -p 67955 -L -o pid,tid,pcpu | sort -nr -k3