性能测试中性能瓶颈分析5个层面

对于一次用户不友好的操作(页面响应时间过长...),我们可以从如下几个方面对涉及该应用的不同层、不同角度对相关性能瓶颈的影响因素进行排查:

硬件瓶颈

cpu

内存

磁盘io

网络io

如果是某个硬件指标有问题,需要深入的进行分析

网络瓶颈

局域网可忽略网络因素

防火墙、动态负载均衡器、交换机等设备

带宽利用率等指标查看

服务器操作系统瓶颈

物理内存不足时,虚拟内存设置也不合理,虚拟内存的交换效率就会大大降低,从而导致行为的响应时间大大增加

中间件瓶颈

参数配置

数据库:慢查SQL,命中率(带缓存、不带缓存等场景),锁、参数设置

tomcat配置

线程池、连接池、GC等,如果是这些指标问题,需要深入分析。

...

应用瓶颈

sql语句

数据库设计

业务逻辑

算法、缓冲、缓存、同步或异步等

...

具体参见下图

解决思路

CPU

CPU资源利用率很高的话,需要看CPU消耗User,Sys,Wait这几种状态下的具体情形:

情形1:如果CPU User非常高,需要查看消耗在哪个进程,可以用top(linux)命令看出,接着用top –H –p 看哪个线程消耗资源高

情形2:如果是java应用,就可以用jstack看出此线程正在执行的堆栈,看资源消耗在哪个方法上,查看源代码就知道问题所在;

情形3:如果是c++应用,可以用gprof性能工具进行分析。

情形4:如果CPU Sys非常高,可以用strace(linux)看系统调用的资源消耗及时间。

情形5:如果CPU Wait非常高,考虑磁盘读写了,可以通过减少日志输出、异步或换速度快的硬盘。

Memory

内存问题主要看某个进程占用内存是否非常大以及是否有大量swap(虚拟内存交换)。

磁盘I/O

磁盘I/O最显著的指标是繁忙率,可以通过减少日志输出、异步或换速度快的硬盘。

网络I/O

网络I/O主要考虑传输内容大小,不能超过硬件网络传输的最大值70%,可以通过压缩、减少内容大小、在本地设置缓存以及分多次传输等。

内核参数

内核参数一般都有默认值,这些内核参数默认值对于一般系统没问题,但是对于压力测试来说,可能运行的参数将会超过内核参数,导致系统出现问题,可以用sysctl来查看及修改。

JVM

jvm主要分析GC/FULL GC是否频繁,以及垃圾回收的时间,可以用jstat命令来查看,对于每个代大小以及GC频繁,通过jmap将内存dump,再借助工具HeapAnalyzer来分析哪地方占用的内存较高以及是否有内存泄漏可能

线程池

如果线程不够用,可以通过参数调整,增加线程;

对于线程池中的线程设置比较大的情况,还是不够用可能的原因是:某个线程被阻塞来不及释放,可能在等锁、方法耗时较长、数据库等待时间很长等原因导致,需要进一步分析才能定位。

JDBC连接池

连接池不够用的情况下,可以通过参数进行调整增加;

但是对于数据库本身处理很慢的情况下,调整没有多大的效果,需要查看数据库方面以及因代码导致连接未释放的原因。

SQL

SQL效率低下也是导致性能差的一个非常重要的原因,可以通过查看执行计划看SQL慢在哪里,一般情况,SQL效率低下原因主要有:

(1) 未建索引,会产生全表扫描

(2) 未利用索引,会产生全表扫描,具体示例如下:

substring(card_no,1,4)=′5378′产生全表扫描

amount/30< 1000产生全表扫描

convert(char(10),date,112)=′19991201′产生全表扫描

where salary<>3000产生全表扫描

name like ‘%张’产生全表扫描

first_name + last_name =’beill cliton’产生全表扫描

id_no in(′0′,′1′)产生全表扫描

select id from t where num=@num有参数也会产生全表扫描

(3) 使用效能低的索引,示例如下:

oder by 非聚族索引,索引性能低

username=’张三’ and age>20,字符串索引低于整形索引

表中列与空NULL值,索引性能低

尽量不要使用IS NULL或IS NOT NULL,索引性能低

(4) 数据量

所有数据量 select *很多列产生大量数据

select id,name表中有几百万行,产生大量数据

嵌套查询先不过滤数据,后过滤数据产生大量无用的数据

关联查询多表进行关联查询,先过滤掉小部分数据,再过滤大部分数据大量关联操作

大数据量插入一次次插入产生大量日志,消耗资源

(5) 锁

锁等待update account set banlance=100 where id=10产生表级锁,将会锁住整个表

死锁A:update a;update b;B:update b;update a;将会产生死锁

游标Cursor Open cursor,fetch;close cursor性能很低

临时表create tmp table 创建临时表产生大量日志

drop table删除临时表需要显示删除,避免系统表长时间锁定

(6) 其他

exist 代替 INselect num from a where num in(select num from b)in会逐个判断,exist有一条就结束

exist 代替select count(*)判断记录是否存在count(*)将累加计算,exist有就结束

between代替INID in(1,2,3)IN逐个判断,between是范围判断

left outer join 代替Not INselect ID from a where ID not in(select b.Mainid from b)NOT IN逐个判断,效率非常低

union all 代替unionselect ID from a union select id from b union删除重复的行,可能会在磁盘进行排序而union all只是简单的将结果并在一起

常用SQL尽量用绑定变量方法insert into A(ID) values(1)直接写SQL每次都要编译,用绑定变量的方法只编译一次,下次就可以用了

策略

日常化的内网的性能测试+定期的真实环境的业务性能测试

你可能感兴趣的:(性能测试中性能瓶颈分析5个层面)