如何做性能测试

性能优化的常见概念

吞吐量(TPS, QPS):简单来说就是每秒钟完成的事务数或者查询数。通常吞吐量大表明系统单位时间能处理的请求数越多,所以通常希望TPS越高越好

响应时间:即从请求发出去到收到系统返回的时间。响应时间一般不取平均值,而是要去掉不稳定的值之后再取均值,比如常用的90%响应时间,指的就是去掉了10%不稳定的响应时间之后,剩下90%的稳定的响应时间的均值。从聚类的观点看,其实就是去掉离群点。

错误率:即错误请求数与总请求数之比。随着压力增加,有可能出现处理请求处理不过来的情况,这时错误数会不断增加。

三者有极大的关联,任何孤立的数据都不能说明问题。典型的关系是,吞吐量增加时,响应延迟有可能增加,错误率也有可能增加。因此,单拿出一个10w的TPS并不能说明问题。

性能调优的思路

一般情况,调优需要有个前提条件,即无论是用线上的真实流水还是线下的压力测试让问题扩大化,明显化。

根据这些比较明显的现象去初判问题,收集证据去验证初判结果成立,然后分析现象产生的原因,并尝试解决问题。


1.性能摸底测试

对于新上的系统或者是有过较大代码改动的系统来说,做一次摸底测试还是很有必要的。一般来说,期望摸底的测试是一次对单机的压力测试。压力测试可以帮你大概搞清楚系统的极限TPS是多少,在压力上来时有没有暴露一些错误或者问题,系统大致的资源占用情况是什么,系统可能的性能瓶颈在哪。

如下是一次摸底测试的配置和结果。这是用12000并发用户对10台机器压测的结果,可以看出,TPS到7w多,平均响应时间为82ms,错误率在2.5%。

从图中还可以得到哪些信息?首先,TPS在后期迅速下落,实际上已经支撑不了如此大的并发量,即进入崩溃区,这里有几个可能,一是系统根本承受不了如此大的并发量,二是系统中间有问题导致TPS下跌。其次,随着时间增长,错误率显著增加,说明系统已经处理不了如此多的请求。结合前面两点以及相对平稳的平均响应时间,大致可以推断系统没法承受如此大的并发。另外,由于是10台机器,单台的TPS大概在7000多,今后的调优可以以此为依据。

对于应用的特点,也要在这时候分析出来,即应用可能占用的资源。比如是CPU密集型应用还是IO密集型应用(还可以细分为是磁盘密集还是网络 )






2.定义性能优化的目标

经常听到人说,做个性能优化,吞吐量越高越好;或者做个性能测试,目标TPS是50000。可实际拿到这个信息,能够做性能测试吗?这个目标足够清晰吗?

事实上,在我看来,未定义清晰的目标去做性能测试都是耍流氓。

性能优化的目标一般是吞吐量达到多少,90%响应时间小于多少,错误率小于多少。同时还需要关注其他的性能指标,cpu使用情况,内存使用情况,磁盘使用情况,带宽使用情况等。对于摸底测试已经发现问题的,可以针对该问题专门优化,比如负载较高,cpu消耗过大,则目标可能是TPS,响应时间以及错误率不变的情况下降低CPU负载。或者内存增长过快,gc较为频繁,则目标可能是找出可能的内存泄露,或者进行相关的jvm内存调优。总之,目标可以比较灵活调整,但一定要明确。

3.分析

分析的过程较为灵活,基本上是一千个系统有一千种表现。这里很难一一说明。仅谈谈一些常见的方法,工具以及思路。

针对CPU

针对cpu的监控,其实linux已经提供了两个比较好用的工具,一个是top,一个是vmstat。关于这两个命令就不细说了,参考这里top(http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/top.html),vmstat(http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/vmstat.html)

关于cpu主要关注4个值:us(user), sy(system), wa(wait), id(idle)。理论上他们加起来应该等于100%。而前三个每一个值过高都有可能表示存在某些问题。

us过高

a. 代码问题。比如一个耗时的循环不加sleep,或者在一些cpu密集计算(如xml解析,加解密,加解压,数据计算)时没处理好

b. gc频繁。一个比较容易遗漏的问题就是gc频繁时us容易过高,因为垃圾回收属于大量计算的过程。gc频繁带来的cpu过高常伴有内存的大量波动,通过内存来判断并解决该问题更好。

小技巧:如何定位us过高的线程并查看它的状态

a. top命令找到消耗us过高的进程pid

b. top -Hp pid找到对应的线程tid

c. printf %x tid转为16进制tid16

d. jstack pid | grep -C 20  tid16 即可查到该线程堆栈

sy过高

a. 上下文切换次数过多。通常是系统内线程数量较多,并且线程经常在切换,由于系统抢占相对切换时间和次数比较合理,所以sy过高通常都是主动让出cpu的情况,比如sleep或者lock wait, io wait。

wa过高

a. 等待io的cpu占比较多。注意与上面情况的区别,io wait引起的sy过高指的是io不停的wait然后唤醒,因为数量较大,导致上下文切换较多,强调的是动态的过程;而io wait引起的wa过高指的是io wait的线程占比较多,cpu切换到这个线程是io wait,到那个线程也是io wait,于是总cpu就是wait占比较高。

id过高

a. 很多人认为id高是好的,其实在性能测试中id高说明资源未完全利用,或者压测不到位,并不是好事。


针对内存

关于java应用的内存,通常只需要关注jvm内存,但有些特殊情况也需要关注物理内存。关于jvm内存,常见的工具有jstat(http://blog.csdn.net/fenglibing/article/details/6411951), jmap(http://www.cnblogs.com/ggjucheng/archive/2013/04/16/3024986.html), pidstat(https://linux.cn/article-4257-1.html), vmstat, top

jvm内存

异常gc :

a. 通常gc发生意味着总归是有一块区域空间不足而触发gc。而许多导致异常gc的情况通常是持有了不必要的引用而没有即时的释放,比如像cache这样的地方就容易处理不好导致内存泄露引发异常gc。

b. 有可能是程序的行为是正常的,但是由于没有配置对合适的gc参数导致异常gc,这种情况通常需要调优gc参数或者堆代大小参数。

c. Full gc 发生的情况:  

  • 永久代满
  • 年老代满
  • minor gc晋升到旧生代的平均大小大于旧生代剩余大小
  • CMS gc中promotion fail或concurrent mode fail

OOM

a. OOM经常伴随着异常gc,之所以单独拿出来讲,是因为它的危害更大一些,异常gc顶多是收集速度过快或者回收不了内存,但是起码有个缓冲时间,但是出了OOM问题就大了。至于各种类型的OOM如何区分,如何发生,请参考这里(http://www.jianshu.com/p/2fdee831ed03),算是总结得比较全面的。对于常见的OOM,基本上可以一下子指出问题所在。

b. heap区,对象创建过多或持有太多无效引用(泄露)或者堆内存分配不足。使用jmap找到内存中对象的分布,使用ps找到相应进程及初始内存配置。

c. stack区, 不正确的递归调用。

d. perm区,初始加载包过多,分配内存不足。

e. 堆外内存区,分配ByteBuffer未释放导致。


针对IO

IO分为网络IO和文件IO,针对网络IO比较有用的工具有sar(https://linuxstory.org/generate-cpu-memory-io-report-sar-command/),netstat(https://linux.cn/article-2434-1.html),netstat是一个非常牛逼的命令,可以助于排查很多问题, 针对文件io的工具有pidstat,iostat(http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/iostat.html)

文件IO

a. 从技术上来说,对于大文件IO可以采取的措施是异步批处理,采用异步方式用于削峰并累计buffer,采用批处理能够让磁盘寻道连续从而更加快速。

网络IO:网络IO的问题较为复杂,仅举几个常见的

a. 大量TIME_WAIT。根据TCP协议,主动发起关闭连接的那一方,关闭了自己这端的连接后再收到被动发起关闭的那一方的关闭请求后,会将状态变为TIME_WAIT,并等待2MSL, 目的是等待自己的回执发送到对方。如果在服务器上发现大量TIME_WAIT,说明服务器主动断开了连接,什么情况下服务器会主动断开连接,很可能是客户端忘了断开连接,所以一个典型的案例就是jdbc连接忘记关闭,则数据库服务器可能会出现大量的TIME_WAIT状态。

b. 大量CLOSE_WAIT。CLOSE_WAIT状态,在收到主动关闭连接的一方发出关闭连接之后,被动关闭的一方进入CLOSE_WAIT状态,如果这时候被hang住了没进行后续关闭,则会出现大量CLOSE_WAIT。啥情况会被hang住呢,举几个例子,比如刚刚的忘记关闭数据库连接,在应用服务器这端,大量的浏览器请求进来,由于没有连接池连接被hang住,这时候浏览器等待一定时间超时发送关闭连接请求,而应用服务器这边由于servlet线程被hang住了,自然没有办法走第二个关闭回去。因此在应用服务器出现大量CLOSE_WAIT。另一个例子是httpClient的坑,在调用response.getEntity(); 前都不会做inputStream.close(),如果在调用response.getEntity()前就返回了,就狗带了。(这个例子可以参考http://blog.csdn.net/shootyou/article/details/6615051)


4.优化并重新测试验证



性能调优思路 http://www.voidcn.com/blog/bigtree_3721/article/p-5786972.html

linux下性能监控命令 http://linuxtools-rst.readthedocs.io/zh_CN/latest/advance/index.html

关于JVM CPU资源占用过高的问题排查 http://my.oschina.net/shipley/blog/520062

java排查工具 http://my.oschina.net/feichexia/blog/196575

jvm参数调优 http://www.cnblogs.com/java-zhao/archive/2016/02/08/5185092.html

java linux系统调优工具 https://www.ibm.com/developerworks/cn/java/j-lo-performance-tuning-practice/

gc优化的一些思路 http://mm.fancymore.com/reading/gc%E4%BC%98%E5%8C%96%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%9D%E8%B7%AF.html

性能优化的思路和步骤 http://www.uml.org.cn/j2ee/201602013.asp

性能调优攻略 http://coolshell.cn/articles/7490.html

JVM性能调优入门 http://www.jianshu.com/p/c6a04c88900a

JVM性能调优 http://blog.csdn.net/chen77716/article/details/5695893

Tomcat性能优化 https://yq.aliyun.com/articles/38861?utm_campaign=wenzhang&utm_medium=article&utm_source=QQ-qun&2017323&utm_content=m_14698

面向GC的Java编程 http://blog.hesey.net/2014/05/gc-oriented-java-programming.html

记一次JVM优化过程 http://sunxiang0918.cn/2014/06/27/%E8%AE%B0%E4%B8%80%E6%AC%A1JVM%E4%BC%98%E5%8C%96%E8%BF%87%E7%A8%8B/

Java应用线上问题排查的常用工具和方法 http://blog.hesey.net/2013/09/common-troubleshooting-tools-and-methods-on-java.html

调优历程: 我是怎样将一个系统的性能提高20倍的? http://colobu.com/2014/09/04/how-to-improve-performance-20-times/

HSF的性能优化 https://mp.weixin.qq.com/s/lsq01ZpENVj540VulcreVw

版权声明:本文为转载至笨狐狸博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liweisnake/article/details/51683090
1 综述 1.1 什么是性能测试 检验系统的性能是否符合要求的测试。包括压力测试、负荷测试、可靠性测试、稳定性测试...... 1.2 性能测试包括哪些方面的测试 速度:服务响应速度 容量:最大支持用户数 可靠性:高负荷运行、长时间运行 1.3 性能测试的目的 (举例) 测算系统的性能指标 查找系统的性能瓶颈 给出较适合的软硬件配置方案 检验硬件配置能否满足客户要求 系统调优(硬件调优、数据库调优) 出一份报告给客户看 1.4 性能指标 (举例) 平均响应时间(秒) 成功率(%) 系统最大处理能力(请求/秒) 系统支持的最大并发用户数 系统预期响应时间(秒) 1.5 性能测试过程 确定目的 设计方案 测试实施 数据分析 2 性能测试过程详述 2.1 确定目的 2.1.1 如何确定测试目的 问主管 问项目经理 问市场人员 问客户 看需求规格说明书 看系统设计文档 靠经验 2.1.2 确定分析方法 需要收集哪些数据 由这些数据怎样分析出测试目的 2.1.3 注意事项 并非所有目的都是合理的(典型例子:测一下所有用户同时点击某个功能) 要找到真正的目的,而不是光问出一句话,有时候,一个人说的并不是他真正要的 各种方法所收集到的目的很可能是不同的,要综合分析,并与相关人员确认 2.2 设计方案 2.2.1 选择具有代表性的功能 最常用的 最耗资源的 2.2.2 设计测试环境 各台机器软硬件配置 系统的各个程序运行在哪台机器上 2.2.3 选定测试工具 通常是选用现成的测试工具,例如loadrunner,但也可能需要自己编写 2.2.4 设计测试步骤 系统运行的步骤 测试数据(界面输入的数据,数据库表中的记录数、索引情况) 2.2.5 确定要记录的原始数据 由测试目的决定 举例: 成功次数、失败次数 测试总时长 CPU占用率(平均、最大) 内存占用 磁盘I/O 2.2.6 注意事项 一般来说,系统的各个程序运行在哪台机器上,在这个阶段可以初步确定,但在测试实施阶段可能还要作出调整 确定数据库表的记录数时,采用从严的原则,在客户实际使用可能产生的数据量的基础上乘以1.5到10倍 确定需要记录哪些原始数据时,采用从宽的原则,即不确定是否需要时,尽量记录下来 2.3 测试实施 2.3.1 搭环境 2.3.2 运行测试工具,记录原始数据 2.3.3 对原始数据进行初步分析 根据成功、失败次数确定本组数据是否有效(成功率大约95%,成功次数大于20) 根据成功、失败次数确定是否需要调整一组数据的测试时长 根据数据的发散情况确定本组数据是否有效 根据前后数据的对比确定本组数据是否有效 根据前后数据的对比确定是否需要在同样情况下再次测试 根据CPU占用率确定下一步的负荷 ...... 2.3.4 重复上面2步 2.4 数据分析 根据原始数据计算出性能指标,对当初确定的目的作出一个结论 3 性能测试的误区 性能测试主要就是测试工具的使用 测试工具可以自动生成我所需要的报表 我不好性能测试,是因为对测试工具不熟悉 4 常见问题 主管要我性能测试(或压力测试、负荷测试),我该怎么办? 我用工具测了一些数据出来,我要怎样分析?我们的系统到底性能怎么样?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值