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(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使用。