赞
踩
随着科技的发展,我们正在进入一个新时代:万物互联时代。在这个时代,网络的响应速度就尤为的重要,想要达到这个目的就需要用到我们本篇文章的主角-性能测试。那么,什么叫性能测试呢?
性能测试是通过自动化的方式,对系统的各项性能指标进行定量或者定性的过程。性能测试的主要目的是为了识别软件应用程序中的性能瓶颈,主要包括负载测试、压力测试、峰值测试、耐久性测试、扩展性测试等类型。
负载测试:检查应用程序在预期用户负载下执行的能力,目标是在软件应用程序上线前识别性能是否达到预期。
压力测试:在极端负载下测试应用程序的执行能力,用以了解应用程序如何处理高流量、高并发的数据,确定应用程序的瓶颈。
峰值测试:测试软件对用户产生的负载突然出现较大峰值的反应。
耐久性测试:用于检查应用程序在长时间内处于高负载的情况下的执行能力。
扩展性测试:确定软件应用程序在用户负载很大的情况下,是否可以进行动态扩展,有助于规划软件系统的扩容。
通常软件测试被分为四个阶段:单元测试、集成测试、系统测试和验收测试。
那么问题来了,在哪个阶段开展性能测试更好呢?
目前大部分的公司都是在集成测试完成后才开始进行性能测试,甚至有些中小型公司都是在系统测试完成以后才开始做性能测试,那么即使发现系统存在性能缺陷,在定位问题的时候也会非常费力。目前软件架构逐渐成熟,从最开始的单体架构逐渐到分布式架构,再到微服务,现在又在推广Serverless架构,导致软件架构越来越庞大。当一段因为使用了不当的算法而导致执行效率很低的代码藏身于一个庞大的系统中时,找出它是非常困难的。
便于理解,我们先讲一个四叶草的故事:
传说中的四叶草(Clover)是夏娃从天国伊甸园带到⼤地上,花语是幸福。⼜名三叶草。通常只有3瓣叶⼦,找到4瓣叶概率很⼩,找到5瓣叶的概率更低,找到6瓣叶的概率只有⼗万分之⼀,隐含得到幸福及上天眷顾。
图片来源于网络,如有侵权,联系作者删除
我也有一个梦想,找到一株四叶草,于是每次去公园都会在路边寻找,但是愿望至今还没有实现。首先四叶草很稀有,其次就算真的存在四叶草,在茫茫的三叶草丛中也很难被发现。
我们把存在性能瓶颈的代码比作一株四叶草,整个系统比作一片草丛,如果草丛中只有孤零零的一株四叶草,或者周围只有几株三叶草,我们去找到这住四叶草的难度就很低,但是如果草丛中有茫茫多的三叶草,再去找到这株四叶草就非常困难。因为他们在某些形态上极其相似,导致定位困难。这种情况有啥好的解决办法呢?
其实最好的方法就是尽早开始核心业务代码的性能测试,从算法和实现方式上就开始进行性能测试。如果每个代码段、每个核心算法、每个实现类的性能都是达标的,那整个系统的性能就不会差。
如果现在问大家,哪些场景需要性能测试?很多人张口就来:接口。没错接口肯定需要性能测试,理论上所有接口都需要做性能测试。除了接口以外,大家还有没有想到其他的呢?
前面也提到了一些性能测试的点:代码段、核心算法、实现类,这些也是优先要考虑做性能测试的。但是还有一些场景经常被大家遗忘,但是又是一个很重要的环节,很多生产的问题都是出在这种环节,那就是中间件。
目前软件开发为了提升性能,会引入各种中间件,例如:Kafka、RabbitMQ等等,这些中间件被大家广泛应用,它本身的性能也是得到了大家的认可,单机都能支持万级甚至十万级的吞吐量。于是很多人就直接拿来就用,往往问题总是出现在容易被忽略的中间件连接上。那么可以支持万级十万级的中间件,为啥还存在性能问题呢?
带着疑问,我们还是先讲一个故事:
大西北有一个李家村,村里有100户人家,整个村子都是以农耕为生,由于常年缺水,地里的庄稼收成很差,村民生活比较贫苦。距离该村子50公里外有一个天然湖泊,水量非常充足,如果可以把湖泊中的水引入到村里,就可以解决吃水的问题了。有一户比较富裕的人家,家主叫李有财,花费重金从湖泊开始铺设水管道,一直延伸到他家里,于是他家的水源问题解决了。其他村民也想效仿,但是碍于资金有限,于是村民们想到一个方案,修建一个蓄水池,将李有财家的水管直接接入蓄水池,再从蓄水池分发到各户人家了。该方案得到全村人的支持,据统计大概300立方的蓄水池就足够全村人正常用水了,于是全村筹资进行建造。蓄水池造好以后,全村傻眼了,根本没有解决吃水问题。由于上游只有一根水管,根本不足以将蓄水池装满,下游还连接着整个村子的所有住户,最后导致整个村子依然没有水。
大家知道为啥吗?难道是300立方的蓄水池太小了?不足以支撑全村人用水吗?其实最根本的原因是水管道太小了,当初的铺设只是供1户人家的使用,现在需要供全村使用,肯定是不够的。
根据上面的故事,我们把他联想到软件开发中来。中间件就像故事中的蓄水池,300立方的体积,如果蓄满水是足够全村使用的,同理,单机十万级吞吐量的中间件,本身的性能是足够支撑一个庞大的系统的,但是如果忽略了上下游的连接,就可能会导致出现严重的问题。
所以,应用了中间件的场景,一定需要考虑做性能测试,每个中间件有成百个配置项,不同的配置项也会带来不同的性能结果。中间件本身的性能可以不用考虑,但是从上游到中间件,再到下游的整个链路一定不能忽视。
开展性能测试一般有以下几个步骤:确定性能需求、设计测试用例、准备测试环境及测试工具、执行测试、分析结果、性能调优、编写测试报告。
我们先讲解第一步,如何确定性能需求?还是讲一个故事:
某货运公司提出一个需求,需要制造一辆卡车用于A城市和B城市之间的货物运输。某汽车制造商制造了一个可以载重5吨的小卡车去交付,交付现场发现货运公司需要拉的货物重达50吨。于是汽车制造商只能重新制造,20天后终于生产出了可以载重达标的货车,于是货运公司进行了验收试验,拉上货物从A城市到B城市,沿途需要经过一个陡坡,这时才发现载重50吨的货车想要爬上陡坡需要至少250匹的马力,但是该货车设计的马力只有190匹,完全不能实现从A城市到B城市的运输,只能再次重新生产。
上面这个故事我们可以看出,载重50吨、马力250匹这两个就属于性能需求。因为如果不能满足这两个性能要求,就不能帮助货运公司实现A城市和B城市之间的货物运输。那么,我们总结一下性能需求需要满足的特点:
上面我们提到,性能测试包括负载测试、压力测试、峰值测试等类型。所以在做性能测试的时候,首先需要明确测试类型,不同场景需要用到不同的测试类型,不同类型的测试方法也有差异,可以选择其中一种类型或者多种类型的组合。上面的故事中需要验证车辆的最大性能拐点和长时间运输的性能效果,所以至少需要用到负载测试和峰值测试。
这里不难理解,上面的故事中汽车制造商制造了三次货车才满足了货运公司最基本的运输需求,就像做软件一样,如果性能需求不足以满足客户的最低要求,只能返工重做。
作为一个性能需求,必须是明确的数字,就像载重50吨、马力250匹一样,只有约定了明确的数字才能做出合格的产品。在软件测试中,某个接口要求响应时间在200ms以内,TPS需要达到1000以上。只有明确了数字,才能更好的展开性能测试。
性能需求必须保证相关人员的意见是一致的,上面的故事中货运公司和汽车制造商需要保持卡车的性能需求的同步和一致性。在软件测试中,性能需求需要从产品、研发、测试、运维等相关的人员保持一致。
那么,获取性能需求的途径都有哪些呢?
就像上面的故事,如果在需求阶段就充分了解了客户的性能需求,就不会返工3次。在实际工作中,一个需求到手以后,需求的提供方不能完全预估出性能的要求,但是作为技术人员需要充分了解需求,再根据需求定义出性能需求。
每个行业都会有众多的公司,每个公司一般也都会有同类的产品,如果想要在众多产品中脱颖而出,最低的标准就是不能比别人差。一旦你的响应速度比别人差很多,是很难留存用户的,根据友商的各种数据可以定义出一些性能需求。
公司内部会有一套自己的性能标准。根据公司现有产品的运行数据进行分析,总结出一套公司标准的数据作为性能需求。
在日常的软件测试工作中,最常用的性能测试工具是LoadRunner和Jmeter。
LoadRunner 是HP(Mercury)公司出品的非常有名的商业性能测试工具,支持多种协议,功能非常强大。支持脚本录制和自主编写脚本,如果想要更充分使用它的功能,对使用者的要求比较高,目前大多介绍性能测试的文章都以该工具为基础。
Jmeter 同样是非常有名的开源性能测试工具,是由Apache组织基于Java语言开发,功能也很完善。一般在介绍Jmeter的时候,都是作为接口测试工具的使用,但实际上,它是一个标准的性能测试工具。它相关的资料也非常丰富,官方文档也很完善。
另外,还有一款很好用的开源性能测试工具:wrk。也许很多人都没有听说过,他是一款轻量级性能测试工具,采用网络异步IO模型,使得系统使用很少的线程模拟大量的网络连接以增大并发量,只支持http协议类型请求,官网文档是这样描述的:
但是,雪球在做性能测试的时候,用的最多的却不是以上3款工具,而是另外一款开源性能测试工具:Locust。下面先通过一组对比简单了解一下这几款工具。
LoadRunner | Jmeter | wrk | Locust | |
---|---|---|---|---|
分布式压力 | 支持 | 支持 | 不支持 | 支持 |
单机并发能力 | 低 | 低 | 低 | 高 |
并发机制 | 进程/线程 | 线程 | 线程 | 协程 |
开发语言 | C/Java | Java | C | Python |
报告与分析 | 完善 | 简单图表 | 简单结果 | 简单图表 |
授权方式 | 商业收费 | 开源免费 | 开源免费 | 开源免费 |
测试脚本形式 | C/Java | GUI | C | Python |
资源监控 | 支持 | 不支持 | 不支持 | 不支持 |
根据上面的对比,我们可以看出Locust的几个特点:
同样,Locust也是有很多缺点的:
雪球选择Locust的主要原因,就是看中了它的这几个优点。雪球用户基数大,有些接口的QPS已经上万,刚好Locust可以满足少量测试资源即可模拟大量并发。对于它的这些缺点,都可以通过其他方式进行弥补。另外,使用Locust作为性能测试工具,还需要注意以下几个方面:
首先需要安装Python3.9+Locust2.9的环境,下面是一个简单的测试脚本:
python
复制代码
from locust import HttpUser, TaskSet, task, between, User class ReplayAction(TaskSet): @task(8) def demo(self): url = '/S/SH600519' headers = {'Content-Type': 'application/json; charset=UTF-8'} try: http_url = User.host + url with self.client.get(http_url, headers=headers, name=url, catch_response=True) as response: if response.status_code != 200: response.failure("Failed") except Exception as e: print("出现异常:%s" % e) class RePlayer(HttpUser): wait_time = between(0, 0) host = "https://xueqiu.com" tasks = [ReplayAction]
ReplayAction:这里定义要压测的接口,继承TaskSet。接口用@task进行装饰,表⽰为⽤户⾏为。根据不同的性能测试需要,这里可以定义多个接口,@task括号⾥⾯参数表⽰该⾏为的执⾏权重,数值越⼤,执⾏频率越⾼,不设置默认是1。self.client调⽤get和post⽅法,和requests类似。在特定的需求下,ReplayAction可以有多个,每个ReplayAction里面装饰的权重分别计算,互相不影响。
RePlayer:继承HttpUser(老版本继承HttpLocust),⽤于设置⽣成负载的基本属性。wait_time是每个负载任务之间最小等待时间和最大等待时间(老版本需要单独设置,分别是min_wait和max_wait);tasks指向定义了用户行为的类,它是列表格式,可以有多个ReplayAction(老版本为task_set,不是列表格式,只能定义一个ReplayAction,如果想要实现多个的话,需要在ReplayAction中定义tasks,并做task嵌套来完成,如果实现了task嵌套,interrupt()在task class中必须定义,否则进来就出不去了。)
脚本编写完成以后,就需要执行脚本,雪球有专门用于执行性能测试脚本的Linux服务器。将脚本上传至服务器以后,执行以下命令:
css
复制代码
locust -f demo.py --headless -u 1000 -r 100 -t 3m
--headless:非Web UI的方式执行脚本,结果直接在命令行输出(老版本为--no-web)
-u:并发用户数(老版本为-c)
-r:每秒增加的用户数(Locust不是启动后马上就通过设定的并发用户数执行压测,而是逐渐加压,直到增加到设定的并发数为止,这个设置就是每秒加压的数量)
-t:设置运行的时间
由于Locust是借助于协程实现并发,所以通常情况需要用到分布式进行压测,分布式的主从启动脚本略有不同:
Master:
css
复制代码
locust -f demo.py --master --headless -u 1000 -r 100 -t 3m --expect-workers=1
Slave:
css
复制代码
locust -f demo.py --worker --headless -u 1000 -r 100 -t 3m --master-host=xx.xx.xx.xx
--master:表示该进程是主进程,需要优先启动主进程,启动以后主进程进入等待状态,直到连接了指定量的从进程以后才开始工作。
--expect-workers:表示等待几个从进程连接后再开始测试,从进程个数达到要求后会立即开始执行,不设置默认为1(老版本为--expect-slaves)。
--worker:表示该进程是从进程(老版本为--slave)。
--master-host:表示连接主进程的IP,不设置表示连接本机
等待程序执行完成后,命令行会显示本次执行的结果,如下:
性能测试步骤中,还有一个环节是非常重要的,那就是分析结果环节,下面我们重点讲一下性能结果都有哪些需要注意的。
相信大家都吃过国内很出名的火锅连锁某某捞,大部分人在用餐的时候应该都需要排号等位吧,我最长一次排了近3个小时。大家有没有想过,如果一个面馆,让你排队三个小时才能吃上一碗面,你应该转头就走了,为啥某某捞就能心甘情愿的排队三个小时呢?
上面的问题先思考着,下文都简称一个餐厅,我们先做一些假设:
当餐厅只有2桌人用餐的时候,只需要2个服务员提供服务即可,其他服务员有的在休息,有的在刷手机。1小时后,两桌客人吃完饭走了,在这一小时里整个餐厅只赚了2桌顾客的钱。
当餐厅有7桌人用餐的时候,就需要至少7个服务员提供服务,其他服务员需要临时打打杂。1小时后,这7桌客人也吃完饭走了,那么在这一小时里整个餐厅赚了7桌顾客的钱。
由于这个餐厅有10个服务员,所以当餐厅有10桌人用餐的时候,10个服务员都需要去提供服务,餐厅在这1小时里可以赚10桌顾客的钱。
通过上面的几个场景,我们可以看出,同样是一个小时,餐厅可以根据顾客的数量不同来赚取不同的钱,随着顾客人数增多,餐厅的工作效率也是逐渐提高,但是每桌顾客的用餐时间都是1小时。
一个新的场景出现了,本来餐厅一个人没有,但是突然之间来了11伙人用餐,前10桌人分别进入餐厅用餐了,剩下这一伙人由于没有餐桌和服务员,只能排队等位,等到那10桌吃完以后才能用餐。前10伙人的用餐时间依然是1个小时,但是最后这一伙人的用餐时间变成了等位1小时+用餐1小时,也就是2小时。
本餐厅的生意非常火爆,突然之间来了35桌人用餐,前10桌人进去用餐,其他25桌人只能外面排号,根据上面的情况我们不难算出,排号1-10的人,他们用餐时间是排号1小时+用餐1小时,也就是2小时。排号11-20的人,他们用餐时间是排号2小时+用餐1小时,也就是3小时,同理排号21-25的人,他们排号的时间就要3个小时,已经超过了忍耐的最长时间,于是他们愤怒的走了。
看到了这里,大家是不是觉得餐厅的排号等位有点像性能测试的场景,我们根据以上的场景提取一些关键性的名词解释吧。
吞吐量:单位时间内处理事务的数量。通常单位时间都按1秒统计,也就是性能测试中经常提起的名词:TPS(每秒处理事务的数量)。通过上面的场景,我们可以计算出该餐厅的最大吞吐量为:10桌/小时。
响应时间:指某个请求或操作从发出到处理,再到接收到反馈所消耗的总时间。通过上面的场景,我们可以认为用餐时间就是响应时间,直接就餐的人响应时间就是1小时,排号1-10的人响应时间就是2小时,以此类推。
平均响应时间:每个请求的响应时间之和除以总请求次数就是平均响应时间。这个指标也是目前大多公司做性能测试中的主流指标之一。
最小响应时间:所有请求中,最小的响应时间。
最大响应时间:所有请求中,最大的响应时间。
90%响应时间(P90) :这个指标在性能测试中经常被大家忽视,不知道这个指标是用来干什么的,甚至不知道这个指标是如何计算的。它的计算规则其实很简单,总请求中按照响应时间从小到大排序,取前90%请求的平均响应时间就是这个指标的值。到现在是不是还不知道有什么作用?
通过上面的图,我们可以看出,有两组测试数据,他们的平均响应时间都是7,那么你们认为哪次结果更理想呢?现在我们通过上面的计算方式,计算一下90%响应时间。
通过上图看出,我们去掉了最后10%的数据,然后再求平均值,这个时候我们发现,90%响应时间分别是5.78和6.78,是不是发现这两次的数据有明显的差距,这能说明什么呢?
假如在一次实际的性能测试中,某接口请求了1万次,测试结果中最小响应时间为12ms,最大响应时间为15s,平均响应时间为1.1s,90%响应时间为500ms,我们可以看到最小响应时间和最大响应时间的偏差非常大,这时候我们是不是对平均响应时间的指标数值表示怀疑呢?
再来一个例子,东奥会刚刚结束不久,我们在看比赛的时候,经常听到类似的话“去掉一个最低分,去掉一个最高分,该选手最终得分为”。这句话在各大赛场经常能听到,为啥要去掉一个最低分和最高分呢?因为这样可以去掉极端数据对选手得分的影响,能够尽量保证选手所得分数反映该选手的正常水平。
再回到这个问题上,90%响应时间这个指标其实是验证平均响应时间的准确性的,指标越接近平均响应时间,越能证明平均响应时间的准确性和可靠性。那么又有人要问了,直接用这个指标替换平均响应时间是否可以?答案是否定的。还拿上面的例子来说,15s的最大响应时间它是真实存在的,不能忽略该请求对整个系统的影响。那么就引出另一个问题了,如果90%响应时间和平均响应时间差距较大该如何处理?
再回到餐厅等位的问题上,假如有一伙人他们到餐厅排一个号以后就去商场逛街了,逛完街又去看了场电影,看完电影后才回来吃饭,前前后后这伙人从排号到吃完饭用了7个小时,如果这时候计算餐厅一天的平均用餐时间,会因为这一个场景影响整个数据的准确性。我们可以通过两种办法解决这个问题:第一种办法,我们可以计算前几天每天的平均用餐时间;第二种办法,我们可以取之前一个月的所有数据放一起做计算。
看到这里大家是不是明白了呢?在性能测试中,我们也是通过两种情况解决这个问题:第一种,同样的场景多次运行取平均值;第二种,增加运行事务的总数,减少特殊情况对整个数据的影响。
并发用户数:指的是系统可以同时承载的正常使用系统功能的用户的数量。
最大并发用户数:指的是系统可以同时承载的正常使用系统功能的最大用户数量。在上面餐厅的例子中,最大并发用户数就是30。因为如果同时来了超过30人,就必然会有人因为等位时间太长而离开。在性能测试的场景中也是一样,如果超过了最大并发用户数的极限,就会出现响应超时、响应错误、甚至系统崩溃的风险。但是在实际的性能测试场景中,我们都会根据有效的性能需求计算最大并发用户数。比如要求接口响应时间在1秒以内,这时候的1秒就是有效的性能需求。再回到餐厅的例子中,如果要求用户用餐时间在2小时内的最大并发用户数,那么就应该是20,因为一旦超过20就必然会有人用餐时间大于2小时。
最佳并发用户数:这又是一个经常被大家忽视的性能指标,他指的是系统没有资源的浪费,整体效率最高的时候同时承载的用户数量。还是拿餐厅为例子,这个餐厅的最佳并发用户数就是10,因为每小时来10桌人的话,没有人需要等位,并且没有空闲桌子和空闲服务员。
但是往往在实际中这个指标是一个范围,这又是为啥呢?餐厅的服务员也会因为长时间工作导致疲惫,顾客用餐完毕后还需要撤掉餐具,收拾餐桌等工作,所以就不能保证全天候的用餐时间都是1小时,会有一些其他事情导致的时间损耗。所以根据日常的规律,我们可以给出餐厅的最佳并发用户数是9-10。下面我们再看一张图:
这张图是一次真实的性能测试数据分析图,在这张图中我们可以看到,最开始,随着并发用户数的增长,总时间和TPS会相应的增长,但是平均响应时间的变化不大;不过当并发用户数增长到一定程度后,TPS增长明显放缓甚至停止增长,而平均响应时间却进一步延长。如果并发用户数继续增长,TPS已经开始下降,平均响应时间急剧增加。
根据上面的图,我们把并发数分为4个区间:
因此,在性能测试中,最佳并发用户数往往才是更应该考虑和关注的,这个指标更能反应系统的性能数据。
上面的图,还有一个经常被大家忽略的指标,或者根本没有考虑过的指标,我叫它性能面积,把每个区间的TPS和响应时间框出来的面积就叫性能面积。那么性能面积如何反应出系统的性能呢?
上面还有一个问题没有讨论,为啥某某捞就能心甘情愿的排队三个小时呢?大家在某某捞排队都在干什么呢?我来给大家列一下:点菜、吃小吃、做美甲等等。大家有没有发现,等位的时候做一些其他事情,既可以打发时间,又可以为后续的用餐提供准备。点菜本来是用餐的第一个环节,我们在等位的时候做了就可以减少用餐的时间;吃小吃可以让你有一定的饱腹感,进一步减少用餐时间。其实这个也能引出一个和性能相关的概念--分步加载和预加载。这个技术主要应用于前端的性能优化。用户在请求某个前端页面时,如果不能保证页面所有元素都瞬间加载出来,可以先加载出部分内容,其他内容逐步加载;当用户频繁访问同一个页面的时候,可以把一些静态的资源储存到本地,以后这些资源可以直接从本地获取。
本文章简单的描述了如何进行性能测试,其中最主要讲述了在性能测试中经常被大家忽视的点。首先性能测试越早开展越好,如果可以配合开发在Coding环节就介入测试效果会更加明显。其次性能问题千万不要忽视中间件的上下游,往往这种地方出问题会更加致命。另外在结果分析中要善于应用P90等指标辅助分析结果,让测试结果更加趋向真实。好了本次就分享到这,感谢大家阅读,欢迎各路大佬指正。
自动化测试相关教程推荐:
2023最新自动化测试自学教程新手小白26天入门最详细教程,目前已有300多人通过学习这套教程入职大厂!!_哔哩哔哩_bilibili
2023最新合集Python自动化测试开发框架【全栈/实战/教程】合集精华,学完年薪40W+_哔哩哔哩_bilibili
测试开发相关教程推荐
2023全网最牛,字节测试开发大佬现场教学,从零开始教你成为年薪百万的测试开发工程师_哔哩哔哩_bilibili
postman/jmeter/fiddler测试工具类教程推荐
讲的最详细JMeter接口测试/接口自动化测试项目实战合集教程,学jmeter接口测试一套教程就够了!!_哔哩哔哩_bilibili
2023自学fiddler抓包,请一定要看完【如何1天学会fiddler抓包】的全网最详细视频教程!!_哔哩哔哩_bilibili
2023全网封神,B站讲的最详细的Postman接口测试实战教学,小白都能学会_哔哩哔哩_bilibili
如果对你有帮助的话,点个赞收个藏,给作者一个鼓励。也方便你下次能够快速查找。
如有不懂还要咨询下方小卡片,博主也希望和志同道合的测试人员一起学习进步
在适当的年龄,选择适当的岗位,尽量去发挥好自己的优势。
我的自动化测试开发之路,一路走来都离不每个阶段的计划,因为自己喜欢规划和总结,
测试开发视频教程、学习笔记领取传送门!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。