性能优化常见概念
吞吐量(TPS, QPS):简单来说就是每秒钟完成的事务数或者查询数。通常吞吐量大表明系统单位时间能处理的请求数越多,所以通常希望TPS越高越好
响应时间:即从请求发出去到收到系统返回的时间。响应时间一般不取平均值,而是要去掉不稳定的值之后再取均值,比如常用的90%响应时间,指的就是去掉了10%不稳定的响应时间之后,剩下90%的稳定的响应时间的均值。
从聚类的观点看,其实就是去掉离群点。
错误率:即错误请求数与总请求数之比。随着压力增加,有可能出现处理请求处理不过来的情况,这时错误数会不断增加。
三者有极大的关联,任何孤立的数据都不能说明问题。典型的关系是,吞吐量增加时,响应延迟有可能增加,错误率也有可能增加。因此,单拿出一个10w的TPS并不能说明问题。
性能调优思路
一般情况,调优需要有个前提条件,即无论是用线上的真实流水还是线下的压力测试让问题扩大化,明显化。
根据这些比较明显的现象去初判问题,收集证据去验证初判结果成立,然后分析现象产生的原因,并尝试解决问题。
性能摸底测试
对于新上的系统或者是有过较大代码改动的系统来说,做一次摸底测试还是很有必要的。
一般来说,期望摸底的测试是一次对单机的压力测试。压力测试可以帮你大概搞清楚系统的极限TPS是多少,在压力上来时有没有暴露一些错误或者问题,系统大致的资源占用情况是什么,系统可能的性能瓶颈在哪。
定义性能优化的目标
经常听到人说,做个性能优化,吞吐量越高越好;或者做个性能测试,目标TPS是50000。可实际拿到这个信息,能够做性能测试吗?这个目标足够清晰吗?
事实上,未定义清晰的目标去做性能测试都是耍流氓。
性能优化的目标一般是吞吐量达到多少,90%响应时间小于多少,错误率小于多少。
同时还需要关注其他的性能指标,cpu使用情况,内存使用情况,磁盘使用情况,带宽使用情况等。对于摸底测试已经发现问题的,可以针对该问题专门优化,比如负载较高,cpu消耗过大,则目标可能是TPS,响应时间以及错误率不变的情况下降低CPU负载。
或者内存增长过快,gc较为频繁,则目标可能是找出可能的内存泄露,或者进行相关的jvm内存调优。总之,目标可以比较灵活调整,但一定要明确。
分析
分析的过程较为灵活,基本上是一千个系统有一千种表现。这里很难一一说明。仅谈谈一些常见的方法,工具以及思路。
针对CPU:
针对cpu的监控,其实linux已经提供了两个比较好用的工具,一个是top,一个是vmstat。
关于cpu主要关注4个值:us(user), sy(system), wa(wait), id(idle)。理论上他们加起来应该等于100%。而前三个每一个值过高都有可能表示存在某些问题。
us过高:
代码问题。比如一个耗时的循环不加sleep,或者在一些cpu密集计算(如xml解析,加解密,加解压,数据计算)时没处理好
gc频繁。一个比较容易遗漏的问题就是gc频繁时us容易过高,因为垃圾回收属于大量计算的过程。gc频繁带来的cpu过高常伴有内存的大量波动,通过内存来判断并解决该问题更好。
小技巧:如何定位us过高的线程并查看它的状态。
top命令找到消耗us过高的进程pid;
top -Hp pid找到对应的线程tid;
printf %x tid转为16进制tid16;
jstack pid | grep -C 20 tid16 即可查到该线程堆栈
sy过高:
上下文切换次数过多。通常是系统内线程数量较多,并且线程经常在切换,由于系统抢占相对切换时间和次数比较合理,所以sy过高通常都是主动让出cpu的情况,比如sleep或者lock wait, io wait。
wa过高:
等待io的cpu占比较多。注意与上面情况的区别,io wait引起的sy过高指的是io不停的wait然后唤醒,因为数量较大,导致上下文切换较多,强调的是动态的过程;
而io wait引起的wa过高指的是io wait的线程占比较多,cpu切换到这个线程是io wait,到那个线程也是io wait,于是总cpu就是wait占比较高。
id过高:
很多人认为id高是好的,其实在性能测试中id高说明资源未完全利用,或者压测不到位,并不是好事。
针对内存:
关于java应用的内存,通常只需要关注jvm内存,但有些特殊情况也需要关注物理内存。
OOM:
OOM经常伴随着异常gc,之所以单独拿出来讲,是因为它的危害更大一些,异常gc顶多是收集速度过快或者回收不了内存,但是起码有个缓冲时间,但是出了OOM问题就大了。
heap区,对象创建过多或持有太多无效引用(泄露)或者堆内存分配不足。使用jmap找到内存中对象的分布,使用ps找到相应进程及初始内存配置。
stack区, 不正确的递归调用;
perm区,初始加载包过多,分配内存不足;
堆外内存区,分配ByteBuffer未释放导致;
下面是我整理的2023年最全的软件测试工程师学习知识架构体系图 |
只有奋斗过的日子,才会留下无悔的痕迹;只有拼搏过的努力,才能创造出辉煌的未来;不忘初心,坚持不懈,只有勇往直前,才能追逐梦想的脚步。
只有拼尽全力,才能看到梦想的辉煌;只有坚持不懈,才能品味成功的味道;只有勇往直前,才能超越自我的极限。相信自己,奋斗无畏,未来将由你书写!
只有坚持不懈的努力,才能铸就辉煌的未来;只有勇往直前的拼搏,才能收获真正的成功;只有不畏艰难的奋斗,才能追寻到人生的价值。相信自己,勇往直前,你将创造出令人瞩目的成就!