改善性能涉及3种不同的活动:性能监控、性能分析及性能调优。
PS:以下都是Linux系统为准
一、CPU使用率
大多数操作系统的CPU使用率分为用户态CPU使用率和系统态CPU使用率。
用户态CPU使用率是指执行应用程序代码的时间占总CPU时间的百分比。
系统态CPU使用率是指执行操作系统调用的时间占总CPU时间的百分比。
系统态CPU使用率高意味着共享资源有竞争或者I/O设备之间有大量的交互。既然原本用于执行操作系统内核调用的CPU周期也可以用来执行应用代码,所以理想情况下,应用达到最高性能和扩展性时,它的系统态CPU使用率为0%。所以提高应用性能和扩展性的一个目标是尽可能降低系统态CPU使用率。
对于计算密集型应用来说,不仅要监控用户态和系统态CPU使用率,还要进一步监控每时钟指令数(Instructions Per Clock,IPC)或每指令时钟周期(Cycle Per Instruction,CPI)等指标。这两个指标对于计算密集型应用来说很重要,因为现代操作系统 自带的CPU使用率监控工具只能报告CPU使用率,而没有CPU执行指令占用CPU时钟周期的百分比。这意味着,即使CPU在等待内存中的数据 ,操作系统工具仍然会报告CPU繁忙。这种情况通常被称为停滞(Stall),一旦发生停滞,应付浪费时钟周期。CPU停滞通常会等待(浪费)好几百个时钟周期。因此提高计算密集型应用性能的策略就是减少停滞或者改善CPU高速缓存使用率,从而减少CPU在等待内存数据时浪费的时钟周期。
1、gnome-system-monitor
启动监控CPU使用率
2、vmstat
命令行显示所有虚拟处理器的总CPU使用率
# 每隔1秒统计一次
[root@localhost]# vmstat -t 1
us是用户态CPU使用率
sy是系统态CPU使用率
id是空闲率或CPU可用率
us+sy+id =100 即100%
3、mpstat
命令查看
usr:用户态CPU使用率
sys:系统态CPU使用率
wt:I/O等待时间百分比
idl:CPU空闲时间的百分比
二、CPU调度程序运行队列
运行队列中就是那些已准备好运行、正等待可用CPU的轻量级进程。如果准备运行的轻量级进程数超过系统所能处理的上限,运行队列就会很长。运行队列长表明系统负载可能已饱和。
一般性的指导原则是:
- 如果在很长一段时间里,运行队列的升序一直都超过虚拟处理器个数的1倍,就需要关注了,只是暂时还不需要立刻采取行动。
- 如果在很长一段时间里,运行队列的长度达到虚拟处理器个数的3-4倍或更多时,则需要立刻引起注意或采取行动。
解决运行队列长有两种方法:
- 增加CPU
- 分析系统中运行的应用,改进CPU使用率。Java程序员可以通过更有效的算法和数据结构来实现更好的性能。
vmstat
输出的第一列是运行队列长度
三、内存使用率
系统内存相关的属性,例如页面调度或页面交换、加锁、线程迁移中的让步式和抢占式上下文切换。
系统在进行页面交换或使用虚拟内存时,Java应用或JVM会表现出明显的性能问题。当应用运行所需的内存超过可用物理内存时,就会发生页面交换。当应用耗尽物理内存时,操作系统会将应用的一部分置换到磁盘上的swap空间,通常是应用中最少运行的部分,以免影响整个应用或者应用最忙的那部分。当访问应用中被 置换出去的部分时,就必须将它从磁盘置换进内存,而这种置换活动会对应用的响应性和吞吐量造成很大影响。
JVM垃圾收集器在系统页面交换时的性能也很差,这是由于垃圾收集器为了回收不可达对象所占用的空间,需要访问大量的内存。如果Java堆的一部分被置换出去就必须先置换进内存以便垃圾收集器扫描存活对象,这会增加垃圾收集的持续时间。垃圾收集是一种Stop-The-World(时空停滞)操作,即停止所有正在运行的应用线程,如果此时系统正在进行页面交换,则会引起JVM长时间的停顿。
1、vmstat
监控内存使用率
当系统空闲内存很少时,内存页面换入和换出的速度几乎一样快。
free:可用的空闲内存
si:内存页面换入的量
so:内存页面换出的量
2、pidstat -w
监控锁竞争(让步式上下文切换)
pidstat -w
输出结果中的cswch/s
是让步式上下文切换。
让步式上下文切换浪费的时钟周期,可以由pidstat -w
的让步式上下文切换数除以虚拟处理器的数目得出。(pidstat -w
是所有虚拟处理器的让步式上下文切换)
让步式上下文切换数乘以8000,除以CPU每秒的时钟周期,可以得出让步式上下文切换所耗费的CPU时钟周期百分比。
上图是 3.0GHz,其中1核的CPU虚拟处理器 ,3GHz CPU每秒的时钟周期数为3 000 000 000。
例:204.44(上下文切换数)/ 1(虚拟处理器核心数) = 204.44
(204.44*8000)/ 3 000 000 000 (每秒的时钟周期数)= 0.000545 = 0.05%
一般性准则
:让步时钟周期占用3%-5%或者更多时钟周期,说明java应用正面临锁竞争。
3、pidstat -w
监控抢占式上下文切换
让步式上下文切换是指执行线程主动释放CPU。
抢占式上下文切换是指线程因为分配的时间片用尽而被迫放弃CPU或者被其他优先级更高的线程所抢占。
pidstat -w 也可以监控抢占式上下文切换。nvcswch/s
:每秒被动任务上下文切换数量。
4、监控线程迁移
待运行线程在处理器之间的迁移也会导致性能下降。大多数操作系统的CPU高度程序会将待运行线程分配给上次运行它的虚拟处理器。如果这个虚拟处理器忙,调度程序就会将待运行线程迁移到其他可用的虚拟处理器。线程迁移会对应用性能造成影响,这是因为新的虚拟处理器缓存中可能没有待运行线程所需的数据或状态信息。
一般性准则
:如果横跨多核或虚拟处理器的Java应用每秒迁移超过500次,将Java应用绑定在处理器组上就有益处。
四、网络I/O使用率
分布式Java应用的性能和扩展性受限于网络带宽或网络I/O的性能。
即便用操作系统的内嵌工具,也难以直接识别和监控网络使用率。例如,netstat -i 命令显示 2500包/秒通过网络接口卡,但你无法知道网络使用率是100%还是1%,简单来说,很难用Linux或Solaris的netstat判断应用的性能是否受网络使用率的限制。只能使用其它工具来监控网络I/O作用率。
软件K9Toolkit的nicstat
可以报告网络使用率和网络接口的饱和度。
nicstat命令行语法如下:
nicstat [-hnsz] [-i interface[,...]] | [interval [count]]
-h显示帮助信息 -n仅显示非本地接口 -s显示概要信息 -z跳过0值,-i interface是网络接口设备名。
interval是输出频率(秒) ,count是报告的采样数。
nicstat -i eth0 1
输出含义
Int: 网络接口设备名
rKb/s:每秒读取kb数
wKb/s:每秒写入Kb数
rPk/s:每秒读取的包数
wPk/s:每秒写入的包数
rAvs:每次读取平均字节
wAvs:每次写入平均字节
%Util:网络接口使用率
Sat:饱和度
应用性能改进的考虑
单次读写数据量少而网络读写量大的应用会消耗大量的系统态CPU,产生大量的系统调用。对于这类应用,减少态CPU的策略是减少网络读写的系统调用。此外,使用非阻塞的Java NIO而不是阻塞的java.net.Socket,减少处理请求和发送响应的线程数,也可以改善应用性能。
JDK提供的Java NIO只是一种原始实现,很容易导致Java API的误用而使性能变差,建议使用Java NIO框架。
五、iostat -xm
磁盘I/O使用率
在linux上安装可选包sysstat才能使用iostat.
iostat -xm 5
每5秒的监控磁盘I/O使用率和系统态CPU使用率。(为了易读,去除了值为0的列)
1、从硬件和操作系统上看,下面是一些改进磁盘I/O使用率的策略:
- 更快的存储设备
- 文件系统扩展到多个磁盘
- 操作系统调优使得可以缓存大量的文件系统数据结构
2、 从应用角度看,任何减少磁盘活动的策略都有帮助,例如使用带缓冲的输入输出流以减少读、写操作次数,或在应用中集成缓存 的数据结构以减少或消除磁盘交互。
3、关于磁盘性能,有一个经常被忽视的方法,就是检查磁盘缓存是否开启。开启磁盘缓存可以改善严重依赖磁盘I/O的应用的性能。注意:一旦开启磁盘缓存,意外的电源故障可能会造成数据损坏。
六、其它命令行工具
1、sar
当需要长时间(例如几小时、几天)或者在生产环境监控应用时,许多人会使用sar收集性能统计数据。sar可以指定需要收集的数据。sar可以实时收集这些数据,不过通常事后才会查看。关于sar如何收集、报告性能数据的更多信息可以参考Linux的Sar手册。
sar [options] [-A] [-o file] t [n]
-
n 和 t 两个参数组合起来定义采样间隔和次数,t为采样间隔,是必须有的参数,n为采样次数,是可选的,默认值是1
-
-o file表示将命令结果以二进制格式存放在文件中,file 在此处不是关键字,是文件名
-
options 为命令行选项,sar命令的选项很多,下面只列出常用选项:
-A:所有报告的总和。
-u:CPU利用率
-v:进程、I节点、文件和锁表状态。
-d:硬盘使用报告。
-r:内存和交换空间的使用统计。
-g:串口I/O的情况。
-b:缓冲区使用情况。
-a:文件读写情况。
-c:系统调用情况。
-q:报告队列长度和系统平均负载
-R:进程的活动情况。
-y:终端设备活动情况。
-w:系统交换活动。
-x { pid | SELF | ALL }:报告指定进程ID的统计信息,SELF关键字是sar进程本身的统计,ALL关键字是所有系统进程的统计。
2、top
使用top命令:
top -H
top的每一行就不是显示一个进程,而是一个线程。top -Hp 进程号
.根据进程号进行查询所有线程pstree -p 进程号
根据进程号进行查询所有线程,以树状显示出来