目录:导读
前言
性能案例1:
问题:某次压力测试,同样并发TPS,但前期性能良好,后期数据库CPU飙升
压测会产生大量级的数据,数据增长会带来性能的损耗
压测数据不合理,导致统一设备关联多个用户,服务端不做限制的in查询
不合理分页,未做页数limit,导致将数据库新增数据全部查询
性能案例2:
问题:响应时间过长,什么原因怎么分析?
一般响应时间过长有下面几个原因:
1)服务器硬件资源cpu,内存,磁盘达到瓶颈,可以使用监控命令排查
2)网络问题导致,比如丢包,带宽不够等等
3)线程出现死锁,阻塞等问题可以用jstack查看
4)中间件比如mq消息队列拥堵排队等
5)数据库层面sql不够优化,没有索引,联合索引失效等,数据库连接数不够。
性能案例3:
问题:压力测试中TPS一直上不去
这个原因比较多,压测整个链路上任何一个环节有瓶颈或者问题都有可能导致
首先是压力机压力不够,比如用我们笔记本基本压不到那么高TPS, 所以我们公司有自己的压测平台,分布式集群压测。
1)网络带宽,单位时间内网络传输数据量过大,超过带宽处理能力
2)数据库连接数太少,最大连接数不够
3)Cpu,内存,磁盘硬件资源达到瓶颈
4)中间件redis也有可能存在瓶颈比如缓存穿透,缓存过期等等
5)存在大量线程阻塞,线程死锁等
6)中间件消息队列拥堵
性能案例4:数据库CPU高
问题现象:后台指令发送满负荷工作时,数据库CPU高。
问题原因:后台指令发送线程每次对全量查询结果排序,结果集很大,然后取一条记录;索引区分度不高,满负荷执行时;查询频率很高;压测显示,并行发送指令的后台线程越多,数据库CPU越高,效率越低。
解决方法:
去掉ORDER BY,增加索引后,效果不明显。因为结果集大和查询频繁两个问题没有解决,因此考虑使用设计新的方案。
新方案:设计指令发送线程池,生产者线程每台任务服务器只有一个线程,负责查询待发送指令,每次查询50条指令。
每条指令包装成一个Runnable对象,放进ThreadPoolExecutor线程池,线程池大小参数设置为100或200。
每当线程池满时,生产者停止生产指令,休息15秒后继续。消费者线程即线程池里的线程,参数设置为4,8或12(和不同指令类型的指令数据量成正比)。
改进后的方案,数据库CPU降到10%一下,发送效率单机提升6倍,且可线性扩展任务服务器。
性能案例5:
问题:内存溢出(堆溢出、栈溢出、持久代溢出)
解决思路:
1)调整堆内存参数,一般是增加堆内存
2)减少批处理数据量
性能案例6:压测TPS曲线剧烈下降或抖动
问题现象:50并发压测,TPS曲线正常应该是平缓的,波动不大,如果突然出现剧烈下降,并且短时间内无法恢复,则可能存在问题。
问题原因:一般是由于前置或bp的jvm进行垃圾回收,或者日志记录磁盘满导致的。
解决方法:如果不是特别剧烈的波动或者TPS曲线下降后长时间不反弹,则可以忽略该问题。
否则,需要分析曲线下降的时刻,系统当时正在发生的事情。可以通过top命令监控当时CPU占用比价高的线程,也可以kill -3 pid杀javacore来查看线程堆栈。
性能案例7:CPU高
问题现象:50并发压测,监控工具显示bp、前置CPU占用90%以上。
问题原因:业务处理中存在大量CPU计算操作。
解决方法:采用更高效的算法、数据结构替换原来消耗CPU的代码,或者采用新的设计绕过瓶颈代码,比如查找数据的逻辑,可以把List改为Map,以空间换时间;比如用Json报文替换XML报文,提高传输、解析和打印日志的效率。
导致Cpu计算资源高消耗的代码:报文格式转换、加解密、正则表达式、低效的循环、低效的正则表达式。
排查方法:
压测进行时,使用jvisualvm工具远程连接应用,点抽样器àCPU,点快照生成线程快照。采样一段时间后,抽样器会显示各个方法占用cpu时间,可以针对CPU时间占用高的方法进行优化。
使用tprofiler,jprofiler,OracleDeveloperStudio12.6-linux-x86工具分别分析消耗CPU时间长的方法,以上工具分析结果可能有些差别。针对CPU计算耗时最长的方法进行优化。
性能案例8:内存泄漏
问题现象:JVM内存耗尽,后台日志抛出OutOfMemeryError异常 ;
问题原因:内存溢出问题可能的原因比较多,可能是全局的List、Map等对象不断被扩大,也可能是程序不慎将大量数据读到内存里;可能是循环操作导致,也可能后台线程定时触发加载数据导致。
解决方法:对于ibmjdk纯java应用,在jvm启动时设置-XX:+HeapDumpOnOutOfMemory Error参数,会在内存溢出时生成heapdump文件。使用ha456.jar工具打开heapdump文件,分析大对象是如何产生的。
当然,在heapdump中对象类型可能只是List这种结构,看不出具体哪个业务代码创建的对象。此时要分析所有的全局对象,列出可疑的List或Map对象,排查其溢出原因。
全局对象、引用的初始化、修改要慎重。建议应用梳理所有可能存放全局对象的代码,统一管控
性能案例9:打开了太多文件
问题现象:采用合理的并发数压测,交易失败,或后台日志报错:To many open files。
问题原因:
读取配置文件或者业务数据文件后,未关闭文件流;
/etc/security/limits.conf中打开文件数配置过小。
解决方法:
使用lsof –p pid 命令查看进程打开的文件,如果大部分文件都是同一类型的文件,说明可能未关闭文件流。找到打开文件的代码,关闭文件流即可。
如果不存在未关闭文件流的问题,且业务本身就需要处理大量文件,则修改/etc/security/limits.conf文件如下内容:
hard nproc 10240
soft nproc 10240
性能案例10:线程阻塞在日志记录上
问题现象:系统响应时间长、通过javacore查看很多线程阻塞在打印日志上。
问题原因:log4j1.x版本较低,性能较差;大报文日志多次输出。
解决方法:
减少无效日志、删除无用日志,减少大日志输出。
升级log4j组件到log4j2,参考log4j2官方文档,配置合理的日志缓冲区,采用高效的Appenders,比如RollingRandomAccessFile。但log4j2仍然采用同步日志,不采用异步日志。
因为网银系统日志量较大,异步日志队列很快就满了,如果单条日志存在大报文,还有可能导致内存溢出,因此不适合采用异步日志。
如果日志量少(压测产生日志的速度,低于日志写入文件的速度),则可以使用异步日志,大幅提高性能。如果日志量较大,则不建议使用异步日志。
排查方法:
JVM启动参数中增加-XX:+HeapDumpOnCtrlBreak,压测进行时,kill -3 pid 杀几个javacore,使用jca457.jar工具打开并分析。推荐使用该工具,因为该工具可以对所有线程状态进行统计,并生成饼状图,方便查看。
压测进行时,使用jvisualvm获取jvm快照,分析线程堆栈。
完整版!企业级性能测试实战,速通Jmeter性能测试到分布式集群压测教程
下面是我整理的2025年最全的软件测试工程师学习知识架构体系图 |
一、Python编程入门到精通
二、接口自动化项目实战
三、Web自动化项目实战
四、App自动化项目实战
五、一线大厂简历
六、测试开发DevOps体系
七、常用自动化测试工具
八、JMeter性能测试
九、总结(尾部小惊喜)
人生最动人的风景,往往藏在最险峻的山巅。当你觉得力竭时,请记住:每一次坚持都在重塑更强大的自己。别问路有多远,只管迈步向前;别怕山有多高,向上攀登就是答案!
你体内沉睡着改变世界的力量!每个清晨都是改写命运的新机会,每次挫折都是精心包装的礼物。当全世界都在说"不可能"时,正是你证明"可能"的最好时机!