寻找性能瓶颈


  cpu消耗分析

在Linux中,cpu主要用于中断,内核以及用户进程的任务处理,优先级为中断>内核>用户进程,如何分析cpu消耗状况,还有三个重要的概念要阐述。

上下文切换

一般情况下每个cpu在同一时间只能执行一个线程(超线程的例外),Linux采用的是抢占试调度,即为每个线程分配一定的执行时间,当到达执行时间,线程中有IO阻塞或者高优先级线程要执行,Linux将切换线程,在切换时存储目前线程的执行状态,并恢复要执行的线程的状态,这个过程就成为上下文切换。对于Java应用,典型的在进行文件IO操作,网络IO操作,锁等待或线程sleep,当前线程会进入阻塞或休眠状态,从而触发上下文切换,上下文协会过多会造成内核占用较多的cpu使用,使得应用的响应速度下降。

运行队列

每个cpu核都维护另一个可运行的线程队列。系统的load主要由cpu的运行队列来决定。

一个4核的cpu,Java应用中启动了8个线程,那么在分配平均的情况下每个cpu的运行队列就有两个线程,假设以上情况维持了1分钟,那么这一分钟你系统的load就会是2(当然这不是绝对)。运行队列值越大,意味着线程要消耗越长的时间才能执行完。建议控制在每个cpu核上的运行队列为1到3个。

利用率

cpu利用率为cpu在用户进程、内核、中断处理、io等待以及空闲五个部分的百分比,这五个值是用来分析cpu消耗情况的关键指标。建议用户进程的cpu消耗/内核的cpu消耗的比率在65%~70%/30%~35%左右。

1.通过top命令查看cpu消耗情况,如图:

Cpu top.jpg

此时,需要关注的是Cpu(s):这一行,其中0.1%us表示用户进行处理所占比例,0.3%sy表示内核线程处理所占比例,0.0%ni表示被nice命令改变优先级的任务所占比例,99.6%id表示空闲时间比例,0.0%wa表示等待io所占比例,0.0%hi表示硬件中断比例,0.0%si表示软件中断比例,0.0%st表示有虚拟cpu的情况,用来指示被虚拟机偷掉的cpu时间

对于多核的cpu,上面的显示会个多个cpu所占用比例的总和,你会看到200%us这样的情况。

1.us

当us值过高时候,表示运行的应用消耗了大部分的cpu,这种情况,对于java而言,可以通过top命令找出cpu消耗严重的线程。可以top命令后shift+h显示线程消耗情况,记录最高的线程id(转16进制)再使用jstack方式dump出应用的Java线程信息。以上方式最好试多几次才确认。

操作us过高的主要原因是线程一直处于可运行状态。通常是这些线程在执行无阻塞、循环、正则或纯粹的计算等动作造成;另外一个可能就是高频繁的GC。

前段时间翼讯平台的企业接口就出现类似的问题,在数据库(sqlserverxxxx)出现异常情况下,企业接口连接池在处理数据库连接关闭时候一直循环,线程一直处理可运行状态,造成企业接口cpu严重消耗。通过上述步骤可以找出异常出现的相关代码。

2.sy

当sy过高时候,表示Linux话费了更多的时间在进行线程切换,java应用造成这个现象的主要原因是启动的线程比较多,且这些线程多数处于不断的阻塞和执行状态的变化过程中,产生大量上下文切换。

可以通过jstack -l 方式dump出Java应用的线程信息,查看线程的状态信息以及锁信息,找出等待状态或锁竞争过多的线程。通过on object monitor可以的堆栈信息,可以找到系统中锁竞争激烈的代码。

  文件IO消耗分析

Linux在操作文件时候,将数据放入文件缓存区,直到内存不够或系统要释放内存给用户进程使用,因此在查看Linux内存状况时候会经常发现可用的屋里内存不多,但是cached用了很多,这是Linux提升文件io速度的一种做法。如物理空闲内存够用,通常Linux上只有写文件和第一次读取文件时会产生真正的文件IO。

要跟踪线程的文件IO的消耗,主要方法是通过pidstat来查找。

.pidstat

输入如pidstat -d -t -p[pid] 5 100 命令即可查看线程的IO消耗情况,如下显示

 01:30:27 PM      TGID       TID   kB_rd/s   kB_wr/s kB_ccwr/s  Command  01:30:28 PM      2760         -      0.00     21.82      0.00  java  01:30:28 PM         -      2760      0.00      0.00      0.00  |__java  01:30:28 PM         -      2764      0.00      0.00      0.00  |__java  01:30:28 PM         -      2765      0.00      0.00      0.00  |__java  01:30:28 PM         -      2766      0.00      0.00      0.00  |__java  01:30:28 PM         -      2767      0.00      0.00      0.00  |__java  01:30:28 PM         -      2768      0.00      0.00      0.00  |__java


其中,kB_rd/s表示每秒读取的kb数,kB_wr/s表示每秒写入的kb数。

在没有安装pidstat的情况下或者内核版本低于2.6.20情况下,可以使用iostat查看,但是只能查看整个系统的文件IO消耗情况。

.iostat

直接输入iostat命令,可查看各个设备的IO历史状况,如下显示

 Linux 2.6.18-194.el5 (YX150)  08/24/2013  _x86_64_ (4 CPU)  avg-cpu:  %user   %nice %system %iowait  %steal   %idle           5.52    0.00    6.31    0.03    0.00   88.14  Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn  sda               6.12         0.83       154.91    2969356  556614982  dm-0             19.40         0.83       154.91    2965098  556614704

在上面的几项指标中,其中Device表示设备卷标名或分区名;tps表示每秒的IO请求数,这也是IO消耗情况中值得关注的数字;Blk_read/s是指每秒读的块数量,通常大小为512字节;Blk_wrtn/s只是每秒写的块数量; Blk_read是指总共读取的块的数量;Blk_wrtn是指总共写入的块数量。

除了上面的方式外,还可以输入iostat -x xvda 3 5 这样的方式来定时采样查看IO的消耗状况,当使用上面的命令方式时,其输出的信息会比较多。

 [root@YX150 esbprogram_top]# iostat -x xvda 3 5  Linux 2.6.18-194.el5 (YX150)  08/24/2013  _x86_64_ (4 CPU)  avg-cpu:  %user   %nice %system %iowait  %steal   %idle           5.52    0.00    6.31    0.03    0.00   88.14  Device:         rrqm/s   wrqm/s     r/s     w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await  svctm  %util  avg-cpu:  %user   %nice %system %iowait  %steal   %idle           0.17    0.00    2.25    0.00    0.00   97.57  Device:         rrqm/s   wrqm/s     r/s     w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await  svctm  %util

其中值得关注的主要有:r/s每秒读的请求数;w/s每秒写的请求数;await平均每次IO操作的等待时间。avgqu-sz等待请求的队列的平均长度,svctm平均每次设备执行IO操作的时间;util一秒钟百分之几用于IO操作。

在使用iostat时候,首先要关注的是cpu中的iowait%所占百分比,当iowait占据了主要的百分比时,就表示要关注IO方面的消耗了,这是可以再通过iostat -x 这样的方式查看具体状况。

对于Java应用如果要找出对于的Java代码,可以结合jstack使用。


你可能感兴趣的:(java,性能,优化)