性能结果分析是性能测试中的一个重要部分,同时也是一个难点。由于不同的软件系统,不同的性能指标,结果分析方法都是不一样的。需要具体问题具体分析。下面将阐述一些性能分析的方法与建议。
1 性能分析的目的
1)找出系统瓶颈(硬件、软件)
2)提出性能优化方案
3)达到合理的硬件和软件配置
4)使系统资源使用达到最大平衡
2 常见性能瓶颈征兆
在性能测试执行过程中,我们需要观察和了解系统的运行状态,如果出现以下征兆,则表示系统可能存在瓶颈。
1) 持续缓慢:应用程序一直特别慢,改变负载,对整体响应时间影响很少;
2) 随着时间推进越来越慢:负载不变,随着时间推进越来越慢,可能到达某个阈值,系统被锁定或出现大量错误而崩溃;
3) 随着负载增加越来越慢:每增加若干用户,系统明显变慢,用户离开系统,系统恢复原状;
4) 零星挂起或异常错误:可能是负载或某些原因,用户看到页面无法完成并挂起,无法消除;
5) 可预见的锁定:一旦出现挂起或错误,就加速出现,直到系统完全锁定。通常要重启系统才解决。
6) 突然混乱:系统一直运行正常,可能是一个小时或三天之后,系统突然出项大量错误或锁定。
3 性能数据解读建议
性能分析过程也是一个解读数据的过程,读懂了数据你就能知道问题出在何处。随着经验的累积将会很容易判断问题的根源,甚至在开发阶段就能对可能出现问题的点打预防针。
性能指标类型 |
标准 |
性能瓶颈征兆 |
分析工具 |
TPS及其波动范围 |
1.Tps符合性能目标 2.Tps轨迹波动平稳 |
1.TPS有明显的大幅波动,不稳定。例如TPS轨迹缓慢下降,缓慢上升后骤降,呈瀑布型,呈矩形,分时间段有规律的波动,无规律的波动等。这些TPS的波动轨迹反映出被测试的性能点存在性能瓶颈,需要性能测试工程师与开发工程师查找性能瓶颈的原因。 2. TPS轨迹比较平稳,但是也存在波动现象。该类波动不明显,很难直接确定是否存在性能瓶颈。我们需要根据其他指标来进行判断。 |
Jmeter/loadrunner |
响应时间 |
90%平均事务响应时间<性能目标 |
1.关注高峰负载时,用户操作响应时间; 2.关注数据库增量,对用户操作响应时间的影响。 |
Jmeter/loadrunner |
Web\DB服务器内存 |
|
1.很高的换页率 2.进程进入不活动状态; 3.交换区所有磁盘的活动次数过高; 4.过高的全局系统CPU利用率; 5.内存不够出错(out of memory errors) |
Nmon/top/vmstat |
WEB\DB服务器CPU |
合理使用的范围在60%至70% |
1.很慢的响应时间 2.CPU空闲时间为零 3.过高的用户占用CPU时间 4.过高的系统占用CPU时间 5.长时间的有很长的运行进程队列 |
Nmon/vmstat/top |
WEB\DB服务器磁盘I/O |
Iowait<30% |
1.过高的磁盘利用率; 2.太长的磁盘等待队列; 3.等待磁盘I/O的时间所占的百分率太高; 4.太高的物理I/O速率; 5.过低的缓存命中率; 6.太长的运行进程队列,但CPU却空闲; |
Nmon/sar/iostat |
Oracle数据库 |
|
1.缓存命中率小于0.90 2.top 10sql耗时高 Oracle数据库的分析和优化,是一门专门的技术,进一步的分析可查相关资料,也可以查看数据库性能分析工具AWR章节。 |
AWR |
4 如何定位性能问题
性能问题的定位排查过程比较复杂,可以采用“拆分问题,隔离分析”的方法进行分析,即逐步定位、从外到内、从表及里、逐层分解、隔离排除。以下分析顺序可供参考。
日志分析--->服务器硬件瓶颈---〉网络瓶颈(对局域网,可以不考虑)---〉服务器操作系统瓶颈(参数配置)---〉中间件瓶颈(参数配置,web服务器等)---〉数据库及应用瓶颈(SQL语句、数据库设计、业务逻辑、算法等)。
以上过程并不是每个分析中都需要的,要根据测试目的和要求来确定分析的深度。整个过程中,要配套使用一些健康工具和日志进行。如: JDK自带的Jconsole,或者JProfiler,来监控服务器性能,oracle的监控工具awr等,具体工具可以参考工具篇。
另外,做性能测试的时候,我们一定要确保瓶颈不要发生在自己的测试脚本和测试工具上。
基于上述思想的指导,在具体执行层面,可以参考如下分析过程:
首先,当我们系统有问题的时候,我们不要急于去调查我们代码,这个毫无意义。我们首要需要看的是操作系统的报告。看看操作系统的CPU利用率,看看内存使用率,看看操作系统的IO,还有网络的IO,网络链接数,等等。通过观察这些数据,我们就可以知道我们的软件的性能基本上出在哪里。比如:
1) 先看CPU利用率,如果CPU利用率不高,但是系统的Throughput和Latency上不去了,这说明我们的程序并没有忙于计算,而是忙于别的一些事,比如IO。(另外,CPU的利用率还要看内核态的和用户态的,内核态的一上去了,整个系统的性能就下来了。而对于多核CPU来说,CPU 0是相当关键的,如果CPU0的负载高,那么会影响其它核的性能,因为CPU各核间是需要有调度的,这靠CPU0完成)
2) 然后,我们可以看一下IO大不大,IO和CPU一般是反着来的,CPU利用率高则IO不大,IO大则CPU就小。关于IO,我们要看三个事,一个是磁盘文件IO,一个是驱动程序的IO(如:网卡),一个是内存换页率。这三个事都会影响系统性能。
3) 然后,查看一下网络带宽使用情况,在Linux下,你可以使用iftop,iptraf,ntop,tcpdump这些命令来查看。或是用Wireshark来查看。
4) 如果CPU不高,IO不高,内存使用不高,网络带宽使用不高。但是系统的性能上不去。这说明你的程序有问题,比如,你的程序被阻塞了。可能是因为等那个锁,可能是因为等某个资源,或者是在切换上下文。
通过了解操作系统的性能,我们才知道性能的问题,比如:带宽不够,内存不够,TCP缓冲区不够,等等,很多时候,不需要调整程序的,只需要调整一下硬件或操作系统的配置就可以了。具体配置项的调优,可以参考配置项调优参考章节。
接下来,我们需要使用性能检测工具,也就是使用某个Profiler来差看一下我们程序的运行性能。如:Java的JProfiler/TPTP/CodeProProfiler,GNU的gprof,IBM的PurifyPlus,Intel的VTune,AMD的接下来,我们需要使用性能检测工具,也就是使用某个Profiler来差看一下我们程序的运行性能。如:Java的JProfiler/TPTP/CodePro Profiler,GNU的gprof,IBM的PurifyPlus,Intel的VTune,AMD的CodeAnalyst,还有Linux下的OProfile/perf,后面两个可以让你对你的代码优化到CPU的微指令级别,如果你关心CPU的L1/L2的缓存调优,那么你需要考虑一下使用VTune。使用这些Profiler工具,可以让你程序中各个模块函数甚至指令的很多东西,如:运行的时间,调用的次数,CPU的利用率,等等。这些东西对我们来说非常有用。
我们重点观察运行时间最多,调用次数最多的那些函数和指令。这里注意一下,对于调用次数多但是时间很短的函数,你可能只需要轻微优化一下,你的性能就上去了(比如:某函数一秒种被调用100万次,你想想如果你让这个函数提高0.01毫秒的时间,这会给你带来多大的性能)。
使用Profiler有个问题我们需要注意一下,因为Profiler会让你的程序运行的性能变低,像PurifyPlus这样的工具会在你的代码中插入很多代码,会导致你的程序运行效率变低,从而没法测试出在高吞吐量下的系统的性能,对此,一般有两个方法来定位系统瓶颈:
1)在你的代码中自己做统计,使用微秒级的计时器和函数调用计算器,每隔10秒把统计log到文件中。
2)分段注释你的代码块,让一些函数空转,做Hard Code的Mock,然后再测试一下系统的Throughput和Latency是否有质的变化,如果有,那么被注释的函数就是性能瓶颈,再在这个函数体内注释代码,直到找到最耗性能的语句。
最后再说一点,对于性能测试,不同的Throughput会出现不同的测试结果,不同的测试数据也会有不同的测试结果。所以,用于性能测试的数据非常重要,性能测试中,我们需要观测试不同Throughput的结果。
4 常见性能问题参考
下面是整理收集的一些常见问题列表,不全,也许并不对,大家可以补充指正。
类别 |
常见性能问题 |
操作系统类 |
1. Sys的CPU使用率过高 2. User的CPU使用率过高,持续大于80%以上 3.可用物理内存不足导致内存溢出 4. 磁盘空间不足导致交易处理失败,性能下降 5. TCP/IP连接数限制导致用户请求失败 6.磁盘IO使用比较繁忙,持续大于70% |
中间件类 |
常用主流中间件:Tomcat、apache、nginx、Weblogic、Jboss等 1.线程不回收导致溢出,引发宕机 2.数据库连接池不释放导致溢出 3.JVM内存参数设置不合理,新生代过大或偏小 4.永久代设置过小,导致栈溢出 5.其它问题 |
应用程序类 |
1. 程序响应时间超长 2. JAVA程序内存溢出,内存中存放大量数据对象 3. JAVA程序循环嵌套过多,过于精细的查询条件,子查询间等待超时 4.程序中存在死循环引起线程死锁,导致CPU使用率达到100% 5.某些返回结果未定义处理方式,导致线程等待,不释放,CPU使用率高 |
数据库类 |
1.SGA分配不合理,需要具体情况具体分析 2.使用全表扫描 3.对于查询业务比较多的表,未建立索引,或建立的索引不合理,在索引列上使用IS NULL和IS NOT NULL 4.存在数据库死锁导致数据库连接超时或不释放。 5.存在过于复杂的计算,导致CPU、内存和IO使用率较高。 6. 数据库读写过于频繁,导致IO使用率比较高 |
其他问题 |
1.网络问题,被测试环境网络环境小于100M 2. 客户端问题等等
|