目的
为了能让小伙伴们快速掌握性能测试,并在工作中顺利开展性能测试,这里专门来给大家来一个速成手册。但是本手册并不会介绍各类性能测试工具的使用,工具使用属于基本能力,请小伙伴自学。
如何切入性能测试
性能测试目标
在开展性能测试之前,首先要摸清楚本次性能测试的目标,通常来说,可以归纳为以下这么几种:
目标:性能摸底
这类目标,一般出现在新框架应用、或者项目刚开发完的初期,架构师或者项目负责人对这个框架或者项目的性能心里没有底,所以想通过性能测试来了解一下目前这套架构的性能咋样。通常没有很明确的性能指标,比如每秒事务数/请求数(TPS/QPS)到多少,响应时间(TRT)在多少以下,因为没有可以参考的指标。所以提出这个性能测试需求的人,只是想了解一下目前这个新系统到底性能咋样,多少压力下会出现瓶颈。
针对这一个目标,我们需要做的就是跟性能测试需求提出的责任人,明确需要进行性能摸底的接口范围是哪些,按照优先级给这些需要进行摸底的接口排好顺序(因为范围会影响测试的工作量)。
确定被测接口是否需要从全链路来压测,还是仅仅需要单接口压测即可。
确定了这些内容,就可以开始编写性能测试方案了。方案主要写清楚以下几点:
- 被测环境(测试环境,还是准发布环境,还是生产环境)
- 压测方法:以50为初始线程数(这个数字可以根据测试环境做调整,因为是摸底,所以这是一个猜测的值,就像请你在1-100之间猜一个数,不需要依据,只要先随便猜一个,再看跟实际值相比是大还是小,再决定猜下一个值),进行正常的压力测试,查看压测工具所提供的TPS的曲线、响应时间的曲线;服务端监控提供的被压测服务器的CPU占用率、CPU队列、内存占用率、虚拟内存占用率、TCP连接数、IO队列、数据库连接、SQL慢查询。如果在压测时间内,资源利用率很低,且TRT比较小(常见为99%线低于3s,且没有请求失败),则认为远没有达到接口性能瓶颈。据此,可以增加线程数(增加20-50为宜)继续压测,直到发现TPS/QPS随着线程数增加已经不再增加,且TRT有变高的趋势,且被测服务端某项资源出现不足的现象,则可以判断为到了接口高负载(heavy load)的瓶颈。可停止压测。每次压测时间不宜低于5分钟,否则时间太短不利于图形趋势分析。
- 压测脚本说明(在完成脚本编写后,将链接贴进方案中,方便归档)
- 压测数据需求(被测接口需要准备哪些数据库数据,以及脚本本身参数化的数据)
- 压测执行时间(需要确定避开其他人使用该环境的时间,防止互相干扰)
- 需要哪些人的配合
基于这个目标的性能分析,主要突出性能拐点,必须说明在多少的TPS/QPS下,接口性能出现下降,主要因素是什么(根据服务端的资源利用率,和开发一起确认原因)。在性能分析报告中,提供整个测试过程的说明,并附上各个压测过程的TPS/QPS,TRT趋势图,以及服务端资源监控的图。最后提供总结:说明在多少TPS/QPS下达到性能瓶颈,主要因素是什么。
在这个目的下,测试人员只出具性能分析报告,而不出性能测试报告,测试报告需要提供“通过/不通过”的结论,而分析报告只说明性能瓶颈和目前分析的产生瓶颈的原因,其意义,是作为架构师或者技术Leader进行性能调优的一个依据。目标:指定负载
这种目标一般会有明确的要求,就像正式的产品需求一样,一般描述为“在达到xx数量的TPS/QPS压力下,平均响应时间(或者95%线或99%线)在xx以内”。这类需求通常出现在新老系统替换,根据线上实际访问压力,有明确的响应时间的要求;或者是甲方客户,明确提出的性能要求。
这类需求明确的,性能测试就会比较好做,在性能测试方案中,压测方法和上一个目标类似,但是观测值是每次压测的TPS/QPS,以及对应的响应时间(平均值,95%线,99%线)。
在执行过程中,根据初始设置的线程数量,观测TPS/QPS,如果TPS未能达到目标,则尝试增加线程数量,直到接近或略微超越目标TPS/QPS。观测此时的响应时间(平均值,95%线,99%线),如果均在目标要求内,则表示达到了压测目标,此时可以结束压测了。
如果达到了目标TPS/QPS,但是响应时间未能达标,则说明有性能问题,可以作为一个bug提出(未能实现性能需求,也属于bug),此时需要连同开发一起来定位性能瓶颈,并尝试优化解决。解决性能bug的过程跟普通bug一样,开发修复后,同样需要再压测一次进行验证bug是否修复。
如果通过增加线程,TPS/QPS始终没能达到目标,在某一低于目标的值附近震荡,响应时间倒是不断升高,那说明有性能问题,TPS/QPS和响应时间两个目标都无法达到,同样需要作为bug提出,并要求开发进行修复。
在这个目的下,测试人员可以出具性能测试报告,内容包括:- 描述性能测试过程(做了几轮,每一轮的线程数,目标接口,运行时间)
- 压测结果(每一轮压测的TPS/QPS over time的图,响应时间over time图,服务器资源监控图)
- 性能分析(对性能瓶颈产生的原因分析)
- 遗留问题
- 测试结论(性能测试通过/不通过)
- 附件(压测脚本和数据作为附件或者链接)
目标:瞬时并发
这个目标很少,通常出现在秒杀这一类的场景中。比如公司业务需要,搞了一场秒杀活动,需要测试验证当前的服务器配置是否足以应付这次活动。
这个目标需要确定并发的量,也就是虚拟线程数量。这个数量通常可以通过咨询业务人员,了解公司这项业务的活跃用户数量,根据这个用户数量可以确定这个线程数。
性能测试方案中,不用像前两个目标这样,分多次去跑,因为线程数为固定值。在固定的线程数量下,对需要并发的接口请求进行同步处理(JMeter中叫同步计时器,LR中叫集合点)。可以设置循环运行多次(比如10次),多次循环来测试并发请求,可以避免一些偶发异常情况对结果的影响。跟前面的压测不同,不是设置持续运行时间来进行压测。
高并发下,一般要求响应时间在人的忍耐极限(一般为10s内),或者是服务端采用限流方式,对超过流量的请求直接返回。(比如直接返回:前方人多拥挤,请稍后再试)。在这样的条件下,服务器不发生资源耗尽导致异常,那就可以算测试通过。
这个目的下的性能测试同样需要出具性能测试报告。报告中需要描述在这个线程下的压测结果,展现服务器资源监控情况,来说明是否可以支撑该次业务活动。
目的:并发功能验证
这种目的严格来说不属于性能测试的范围,它考虑的是某个接口是否可以在多线程下工作正常。因为多线程编程通常会有很复杂的锁机制,程序员很有可能锁操作错误,或者未加锁;包括多线程在处理数据库时的事务独立性(Transaction Isolation)设置不正确,都可能导致程序数据问题。所以需要测试在这些可能出现问题的接口上进行多线程并发访问的测试。这属于是一种功能测试,测试用例可以体现在功能测试用例中。
性能测试环境
性能测试环境一般有两种选择:
- 生产环境
- 测试环境
生产环境能最真实的反应实际线上系统的性能,但是压测所产生的数据容易污染生产环境,而且压测时候会导致生产环境压力过大而使正常用户使用时感受较差(性能下降了,感受很卡)。所以针对这两个问题,通常如此处理:
- 在数据污染方面,通常需要进行数据隔离,比如整个系统设计影子表,带有特殊标记的压测数据不会真正写入生产数据库,而是进入一张影子表,压测完成后清理掉影子表即可。这个需要在系统上线时做好这方面的设计才行。
- 在时间方面,可以错开用户使用的高峰时段,比如半夜、凌晨,或者通知线上系统进入维护时段。
如果没有条件进行生产环境压测,那就只能在测试环境进行压测了。测试环境不会有数据污染和影响用户的问题,但是需要能类比线上环境。也就是说,需要能根据测试环境压测后的结果,估计出生产环境的性能情况。这个比例,一般由技术专家或者架构师给出。测试同学需要在做方案阶段,就明确这个比例关系。如果不能明确如何对比生产环境,那么在测试环境进行的压测其实并无意义。
性能分析
在性能分析过程中,其实有非常多的实际情况需要随机应变,但是2000年初,有大神总结过一个性能分析的通用模型,可以给到大家一些思路,并更好的理解和设计压测,这个模型叫做《理发师模型》。
相信大家都进过或见过理发店,一间或大或小的铺面,1个或几个理发师,几张理发用的椅子和供顾客等待的长条板凳。
在我们的这个理发店中,我们事先做了如下的假设:
- 理发店共有3名理发师;
- 每位理发师剪一个发的时间都是1小时;
- 我们顾客们都是很有时间观念的人而且非常挑剔,他们对于每次光顾理发店时所能容忍的等待时间+剪发时间是3小时,而且等待时间越长,顾客的满意度越低。如果3个小时还不能剪完头发,我们的顾客会立马生气的走人。
通过上面的假设我们不难想象出下面的场景:
- 当理发店内只有1位顾客时,只需要有1名理发师为他提供服务,其他两名理发师可能继续等着,也可能会帮忙打打杂。1小时后,这位顾客剪完头发出门走了。那么在这1个小时里,整个理发店只服务了1位顾客,这位顾客花费在这次剪发的时间是1小时;
- 当理发店内同时有两位顾客时,就会同时有两名理发师在为顾客服务,另外1位发呆或者打杂帮忙。仍然是1小时后,两位顾客剪完头发出门。在这1小时里,理发店服务了两位顾客,这两位顾客花费在剪发的时间均为1小时;
- 很容易理解,当理发店内同时有三位顾客时,理发店可以在1小时内同时服务三位顾客,每位顾客花费在这次剪发的时间仍然是均为1小时;
从上面几个场景中我们可以发现,在理发店同时服务的顾客数量从1位增加到3位的过程中,随着顾客数量的增多,理发店的整体工作效率在提高,但是每位顾客在理发店内所呆的时间并未延长。
当然,我们可以假设当只有1位顾客和2位顾客时,空闲的理发师可以帮忙打杂,使得其他理发师的工作效率提高,并使每位顾客的剪发时间小于1小时。不过即使根据这个假设,虽然随着顾客数量的增多,每位顾客的服务时间有所延长,但是这个时间始终还被控制在顾客可接受的范围之内,并且顾客是不需要等待的。
不过随着理发店的生意越来越好,顾客也越来越多,新的场景出现了。假设有一次顾客A、B、C刚进理发店准备剪发,外面一推门又进来了顾客D、E、F。因为A、B、C三位顾客先到,所以D、E、F三位只好坐在长板凳上等着。1小时后,A、B、C三位剪完头发走了,他们每个人这次剪发所花费的时间均为1小时。可是D、E、F三位就没有这么好运,因为他们要先等A、B、C三位剪完才能剪,所以他们每个人这次剪发所花费的时间均为2小时——包括等待1小时和剪发1小时。
通过上面这个场景我们可以发现,对于理发店来说,都是每小时服务三位顾客——第1个小时是A、B、C,第二个小时是D、E、F;但是对于顾客D、E、F来说,“响应时间”延长了。如果你可以理解上面的这些场景,就可以继续往下看了。
在新的场景中,我们假设这次理发店里一次来了9位顾客,根据我们上面的场景,相信你不难推断,这9位顾客中有3位的“响应时间”为1小时,有3位的“响应时间”为2小时(等待1小时+剪发1小时),还有3位的“响应时间”为3小时(等待2小时+剪发1小时)——已经到达用户所能忍受的极限。假如在把这个场景中的顾客数量改为10,那么我们已经可以断定,一定会有1位顾客因为“响应时间”过长而无法忍受,最终离开理发店走了。
我想并不需要特别说明,大家也一定可以把上面的这些场景跟性能测试挂上钩了。如果你还是觉得比较抽象,继续看下面的这张图:
这张图中展示的是1个标准的性能模型。在图中有三条曲线,分别表示资源的利用情况(Utilization,包括硬件资源和软件资源)、吞吐量(Throughput,这里是指每秒事务数)以及响应时间(Response Time)。图中坐标轴的横轴从左到右表现了并发用户数(Number of Concurrent Users)的不断增长。
在这张图中我们可以看到,最开始,随着用户数的增长,资源占用率和吞吐量会相应的增长,但是响应时间的变化不大;不过当并发用户数增长到一定程度后,资源占用达到饱和,吞吐量增长明显放缓甚至停止增长,而响应时间却进一步延长。如果并发用户数继续增长,你会发现软硬件资源占用继续维持在饱和状态,但是吞吐量开始下降,响应时间明显的超出了用户可接受的范围,并且最终导致用户放弃了这次请求甚至离开。
根据这种性能表现,图中划分了三个区域,分别是Light Load(较轻的压力)、Heavy Load(较重的压力)和Buckle Zone(用户无法忍受并放弃请求)。在Light Load和Heavy Load 两个区域交界处的并发用户数,我们称为“最佳并发用户数(The Optimum Number of Concurrent Users)”,而Heavy Load和Buckle Zone两个区域交界处的并发用户数则称为“最大并发用户数(The Maximum Number of Concurrent Users)”。
当系统的负载等于最佳并发用户数时,系统的整体效率最高,没有资源被浪费,用户也不需要等待;当系统负载处于最佳并发用户数和最大并发用户数之间时,系统可以继续工作,但是用户的等待时间延长,满意度开始降低,并且如果负载一直持续,将最终会导致有些用户无法忍受而放弃;而当系统负载大于最大并发用户数时,将注定会导致某些用户无法忍受超长的响应时间而放弃。
对应到我们上面理发店的例子,每小时3个顾客就是这个理发店的最佳并发用户数,而每小时9个顾客则是它的最大并发用户数。当每小时都有3个顾客到来时,理发店的整体工作效率最高;而当每小时都有9个顾客到来时,前几个小时来的顾客还可以忍受,但是随着等待的顾客人数越来越多,等待时间越来越长,最终还是会有顾客无法忍受而离开。同时,随着理发店里顾客人数的增多和理发师工作时间的延长,理发师会逐渐产生疲劳,还要多花一些时间来清理环境和维持秩序,这些因素将最终导致理发师的工作效率随着顾客人数的增多和工作的延长而逐渐的下降,到最后可能要1.5小时甚至2个小时才能剪完1个发了。
当然,如果一开始就有10个顾客到来,则注定有1位顾客剪不到头发了。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jimmyseraph@testops.vip