mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2025-11-17 14:43:42 +08:00
mod
This commit is contained in:
221
极客时间专栏/软件测试52讲/性能测试篇/28 | 带你一起解读不同视角的软件性能与性能指标.md
Normal file
221
极客时间专栏/软件测试52讲/性能测试篇/28 | 带你一起解读不同视角的软件性能与性能指标.md
Normal file
@@ -0,0 +1,221 @@
|
||||
<audio id="audio" title="28 | 带你一起解读不同视角的软件性能与性能指标" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/4f/a5/4f57c93c124f28c28a394ab6af212ba5.mp3"></audio>
|
||||
|
||||
你好,我是茹炳晟。今天我和你分享的主题是:带你一起解读不同视角的软件性能与性能指标。
|
||||
|
||||
我用三篇文章的篇幅,和你分享了代码级测试的一些基本概念和测试方法,希望可以帮助你解决在实际工作中遇到的问题,如果你感觉还有一些问题没有解决的话,欢迎你给我留言,我们一起去讨论、解决。
|
||||
|
||||
从今天开始,我将和你分享一个新的测试主题:性能测试。这个系列,我准备了七个主题,要和你详细聊聊软件性能测试相关的知识点。
|
||||
|
||||
因为性能测试的专业性很强,所以我会以从0到1的入门者视角,系统性地阐述性能测试的方法以及应用领域,用实例去诠释各种性能指标;我还会分享一些前端和后端性能测试工具的基本原理,并基于LoadRunner去分析一些大型企业性能测试的规划、设计、实现的具体实例;我还会和你分享一些跨国软件公司性能测试卓越中心的实际案例。
|
||||
|
||||
希望这个系列的内容,可以完善你的性能测试知识体系,真真正正地帮你解决实际项目中遇到的问题。
|
||||
|
||||
那么,作为性能测试系列的第一次分享,我会站在全局的视角,帮你梳理软件性能、软件性能测试相关的知识点,让你对那些你或许已经耳熟能详的性能指标有一个更清晰的理解,为你完成后续的性能测试工作打好基础。
|
||||
|
||||
如果你对软件性能的理解还停留在响应时间的快慢上,那么赶紧和我一起开始今天的内容吧。
|
||||
|
||||
**在开始下面的内容前,请你先思考一个问题:当我们谈及软件性能的时候,我们到底谈的是什么?**
|
||||
|
||||
目前,对软件性能最普遍的理解就是软件处理的及时性。但其实,从不同的系统类型,以及不同的视角去讨论软件性能,都会有所区别。
|
||||
|
||||
对于不同类型的系统,软件性能的关注点各不相同,比如:
|
||||
|
||||
- Web类应用和手机端应用,一般以终端用户感受到的端到端的响应时间来描述系统的性能;
|
||||
- 非交互式的应用,比如典型的电信和银行后台处理系统,响应时间关注更多的是事件处理的速度,以及单位时间的事件吞吐量。
|
||||
|
||||
这很容易理解。同样地,对同一个系统来说,不同的对象群体对软件性能的关注点和期望也不完全相同,甚至很多时候是对立的。这里,不同的对象群体可以分为四大类:终端用户、系统运维人员、软件设计开发人员和性能测试人员。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/73/2d/73607121b26944c77f657e62a8894e2d.png" alt="" />
|
||||
|
||||
终端用户是软件系统的最终使用者,他们对软件性能的反馈直接决定了这个系统的应用前景;而,软件开发人员、运维人员、性能测试人员,对性能测试的关注点则直接决定了一个系统交付到用户手中的性能。
|
||||
|
||||
只有全面了解各类群体对软件系统的不同需求,才能保证这个系统具有真正高可靠的性能。所以,接下来我会从这四类人的视角和维度去分享软件性能到底指的是什么。
|
||||
|
||||
## 终端用户眼中的软件性能
|
||||
|
||||
从终端用户(也就是软件系统使用者)的维度来讲,软件性能表现为用户进行业务操作时的主观响应时间。具体来讲就是,从用户在界面上完成一个操作开始,到系统把本次操作的结果以用户能察觉的方式展现出来的全部时间。对终端用户来说,这个时间越短体验越好。
|
||||
|
||||
这个响应时间是终端用户对系统性能的最直观印象,包括了系统响应时间和前端展现时间。
|
||||
|
||||
- 系统响应时间,反应的是系统能力,又可以进一步细分为应用系统处理时间、数据库处理时间和网络传输时间等;
|
||||
- 前端展现时间,取决于用户端的处理能力。
|
||||
|
||||
从这个角度来看,你就可以非常容易理解性能测试为什么会分为后端(服务器端)的性能测试和前端(通常是浏览器端)的性能测试了。
|
||||
|
||||
## 系统运维人员眼中的软件性能
|
||||
|
||||
从软件系统运维(也就是系统运维人员)的角度,软件性能除了包括单个用户的响应时间外,更要关注大量用户并发访问时的负载,以及可能的更大负载情况下的系统健康状态、并发处理能力、当前部署的系统容量、可能的系统瓶颈、系统配置层面的调优、数据库的调优,以及长时间运行稳定性和可扩展性。
|
||||
|
||||
大多数情况下,系统运维人员和终端用户是站在同一条战线上的,希望系统的响应速度尽可能地快。但,某些情况下他们的意见是对立的,最常见的情况就是,系统运维人员必须在最大并发用户数和系统响应时间之间进行权衡取舍。比如,当有两套系统配置方案可以提供以下系统能力的时:
|
||||
|
||||
- 配置方案A可以提供100万并发访问用户的能力,此时用户的登录响应时间是3秒;
|
||||
- 配置方案B可以提供500万并发访问用户的能力,此时用户的登录响应时间是8秒。
|
||||
|
||||
这时,从全局利益最大化角度来看,系统具有更大并发用户承载能力的价值会更大,所以运维人员一般都会选择方案B。
|
||||
|
||||
**目前,有些系统为了能够承载更多的并发用户,往往会牺牲等待时间而引入预期的等待机制**。比如,火车票购票网站,就在处理极大并发用户时采用了排队机制,以尽可能提高系统容量,但却增加了用户实际感受到的响应时间。
|
||||
|
||||
## 软件设计开发人员眼中的软件性能
|
||||
|
||||
从软件系统开发(也就是软件设计开发人员)的角度来讲,软件性能关注的是性能相关的设计和实现细节,这几乎涵盖了软件设计和开发的全过程。
|
||||
|
||||
在大型传统软件企业中,软件性能绝不仅仅是性能测试阶段要考虑的问题,而是整个软件研发生命周期都要考虑的内容,我们往往把围绕性能相关的活动称为“性能工程”(Performance Engineering)。我曾在惠普软件研发中心的性能测试卓越中心负责这方面的技术工作,所以感受颇深。
|
||||
|
||||
在软件设计开发人员眼中,软件性能通常会包含算法设计、架构设计、性能最佳实践、数据库相关、软件性能的可测试性这五大方面。其中,每个方面关注的点,也包括很多。
|
||||
|
||||
**第一,算法设计包含的点:**
|
||||
|
||||
- 核心算法的设计与实现是否高效;
|
||||
- 必要时,设计上是否采用buffer机制以提高性能,降低I/O;
|
||||
- 是否存在潜在的内存泄露;
|
||||
- 是否存在并发环境下的线程安全问题;
|
||||
- 是否存在不合理的线程同步方式;
|
||||
- 是否存在不合理的资源竞争。
|
||||
|
||||
**第二,架构设计包含的内容:**
|
||||
|
||||
- 站在整体系统的角度,是否可以方便地进行系统容量和性能扩展;
|
||||
- 应用集群的可扩展性是否经过测试和验证;
|
||||
- 缓存集群的可扩展性是否经过测试和验证;
|
||||
- 数据库的可扩展性是否经过测试和验证。
|
||||
|
||||
**第三,性能最佳实践包含的点:**
|
||||
|
||||
- 代码实现是否遵守开发语言的性能最佳实践;
|
||||
- 关键代码是否在白盒级别进行性能测试;
|
||||
- 是否考虑前端性能的优化;
|
||||
- 必要的时候是否采用数据压缩传输;
|
||||
- 对于既要压缩又要加密的场景,是否采用先压缩后加密的顺序。
|
||||
|
||||
**第四,数据库相关的点:**
|
||||
|
||||
- 数据库表设计是否高效;
|
||||
- 是否引入必要的索引;
|
||||
- SQL语句的执行计划是否合理;
|
||||
- SQL语句除了功能是否要考虑性能要求;
|
||||
- 数据库是否需要引入读写分离机制;
|
||||
- 系统冷启动后,缓存大量不命中的时候,数据库承载的压力是否超负荷。
|
||||
|
||||
**第五,软件性能的可测试性包含的点:**
|
||||
|
||||
- 是否为性能分析(Profiler)提供必要的接口支持;
|
||||
- 是否支持高并发场景下的性能打点;
|
||||
- 是否支持全链路的性能分析。
|
||||
|
||||
需要注意的是,软件开发人员一般不会关注系统部署级别的性能,比如软件运行目标操作系统的调优、应用服务器的参数调优、数据库的参数调优、网络环境的调优等。
|
||||
|
||||
系统部署级别的性能测试,目前一般是在系统性能测试阶段或者系统容量规划阶段,由性能测试人员、系统架构师,以及数据库管理员(DBA)协作完成。
|
||||
|
||||
## 性能测试人员眼中的软件性能
|
||||
|
||||
从性能工程的角度看,性能测试工程师关注的是算法设计、架构设计、性能最佳实践、数据库相关、软件性能的可测试性这五大方面。
|
||||
|
||||
在系统架构师、DBA,以及开发人员的协助下,性能测试人员既要能够准确把握软件的性能需求,又要能够准确定位引起“不好”性能表现的制约因素和根源,并提出相应的解决方案。
|
||||
|
||||
一个优秀的性能测试工程师,一般需要具有以下技能:
|
||||
|
||||
- 性能需求的总结和抽象能力;
|
||||
- 根据性能测试目标,精准的性能测试场景设计和计算能力;
|
||||
- 性能测试场景和性能测试脚本的开发和执行能力;
|
||||
- 测试性能报告的分析解读能力;
|
||||
- 性能瓶颈的快速排查和定位能力;
|
||||
- 性能测试数据的设计和实现能力;
|
||||
- 面对互联网产品,全链路压测的设计与执行能力,能够和系统架构师一起处理流量标记、影子数据库等的技术设计能力;
|
||||
- 深入理解性能测试工具的内部实现原理,当性能测试工具有限制时,可以进行扩展二次开发;
|
||||
- 极其宽广的知识面,既要有“面”的知识,比如系统架构、存储架构、网络架构等全局的知识,还要有大量“点”的知识积累,比如数据库SQL语句的执行计划调优、JVM垃圾回收(GC)机制、多线程常见问题等等。
|
||||
|
||||
看到如此多的技能要求你可能有点害怕,的确,性能测试的专业性比较强,我经常把优秀的性能工程师比作是优秀的医生,也是这个原因。你需要在实际项目中积累大量的实际案例,才能慢慢培养所谓的“性能直觉”,从我个人的学习路径来讲也是如此。
|
||||
|
||||
天下无难事只怕有心人,所以抓住一切可以充实自己的机会吧,我们终将会破茧成蝶。
|
||||
|
||||
这就是终端用户、系统运维工程师、软件开发工程师,以及性能测试工程师眼中的性能测试了,至此我们也就非常容易理解,不同的群体对同一个系统的性能要求为什么会如此不同。
|
||||
|
||||
现在,**我再来和你说说衡量软件性能的三个最常用的指标:并发用户数、响应时间,以及系统吞吐量**。只要你接触过性能测试,或者你的团队开展过性能测试,你都应该听说这三个指标。但其实很多人对它们的理解还都停留在表面,并没有深入细致地考虑过其本质与内涵,这也导致了性能测试很多时候并没有发挥应有的作用。
|
||||
|
||||
因此,接下来我会和你深入地聊聊这三个指标的内涵和外延,帮助你获得一个全新的认识。
|
||||
|
||||
## 并发用户数
|
||||
|
||||
**并发用户数,是性能需求与测试最常用,也是最重要的指标之一。它包含了业务层面和后端服务器层面的两层含义。**
|
||||
|
||||
- 业务层面的并发用户数,指的是实际使用系统的用户总数。但是,单靠这个指标并不能反映系统实际承载的压力,我们还要结合用户行为模型才能得到系统实际承载的压力。
|
||||
- 后端服务器层面的并发用户数,指的是“同时向服务器发送请求的数量”,直接反映了系统实际承载的压力。
|
||||
|
||||
为了让你更好地理解这两层含义之间的区别,我们先一起来看一个实例:一个已经投入运行的ERP系统,该系统所在企业共有5000名员工并都拥有账号,也就是说这个系统有5000个潜在用户。
|
||||
|
||||
根据系统日志分析得知,该系统最大在线用户数是2500人,那么从宏观角度来看,2500就是这个系统的最大并发用户数。但是,2500这个数据仅仅是说在最高峰时段有2500个用户登录了系统,而服务器所承受的压力取决于登录用户的行为,所以它并不能准确表现服务器此时此刻正在承受的压力。
|
||||
|
||||
假设在某一时间点上,这2500个用户中,30%用户处于页面浏览状态(对服务器没有发起请求),20%用户在填写订单(也没有对服务器发起请求),5%用户在递交订单,15%用户在查询订单,而另外的30%用户没有进行任何操作。那么此时,这2500个“并发用户”中真正对服务器产生压力的只有500个用户((5%+15%)*2500=500)。
|
||||
|
||||
在这个例子中,5000是最大的“系统潜在用户数”,2500是最大的“业务并发用户数”,500则是某个时间点上的“实际并发用户数”。而此时这500个用户同时执行业务操作所实际触发的服务器端的所有调用,叫作“服务器并发请求数”。
|
||||
|
||||
从这个例子可以看出,在系统运行期间的某个时间点上,有一个指标叫作“同时向服务器发送请求的数量”,这个“同时向服务器发送请求的数量”就是服务器层面的并发用户数,这个指标同时取决于业务并发用户数和用户行为模式,而且用户行为模式占的比重较大。
|
||||
|
||||
因此,分析得到准确的用户行为模式,是性能测试中的关键一环。但,获得精准的用户行为模式,是除了获取性能需求外,最困难的工作。
|
||||
|
||||
目前,获取用户行为模式的方法,主要分为两种:
|
||||
|
||||
- 对于已经上线的系统来说,往往采用系统日志分析法获取用户行为统计和峰值并发量等重要信息;
|
||||
- 而对于未上线的全新系统来说,通常的做法是参考行业中类似系统的统计信息来建模,然后分析。
|
||||
|
||||
## 响应时间
|
||||
|
||||
**通俗来讲,响应时间反映了完成某个操作所需要的时间,其标准定义是“应用系统从请求发出开始,到客户端接收到最后一个字节数据所消耗的时间”,是用户视角软件性能的主要体现。**
|
||||
|
||||
响应时间,分为前端展现时间和系统响应时间两部分。其中,前端时间,又称呈现时间,取决于客户端收到服务器返回的数据后渲染页面所消耗的时间;而系统响应时间,又可以进一步划分为Web服务器时间、应用服务器时间、数据库时间,以及各服务器间通信的网络时间。
|
||||
|
||||
除非是针对前端的性能测试与调优,软件的性能测试一般更关注服务器端。但是,服务器端响应时间的概念非常清晰、直接,就是指从发出请求起到处理完成的时间,没有二义性;而前端时间的定义,在我看来存在些歧义。所以,接下来我会和你详细聊聊前端时间这个话题。
|
||||
|
||||
虽然前端时间一定程度上取决于客户端的处理能力,但是前端开发人员现在还会使用一些编程技巧在数据尚未完全接收完成时呈现数据,以减少用户实际感受到的主观响应时间。也就是说,我们现在会普遍采用提前渲染技术,使得用户实际感受到的响应时间通常要小于标准定义的响应时间。
|
||||
|
||||
鉴于此,**我认为响应时间的标准定义就不尽合理了,尤其是对于“接收到最后一个字节”。**
|
||||
|
||||
我来举个实际案例吧。加载一个网页时,如果10秒后还是白屏,那你一定会感觉很慢、性能无法接受。但是,回想一下你曾经上新浪网的经历,当加载新浪首页时,你应该不会感觉速度很慢吧。其实,实际情况是,新浪首页的加载时间要远大于10秒,只是新浪采用了数据尚未完全接收完成时进行呈现的技术,大大缩短了用户主观感受到的时间,提升了用户体验。
|
||||
|
||||
所以,**严格来讲,响应时间应该包含两层含义:技术层面的标准定义和基于用户主观感受时间的定义。而在性能测试过程中,我们应该使用哪个层面的含义将取决于性能测试的类型**。显然,对于软件服务器端的性能测试肯定要采用标准定义,而对于前端性能评估,则应该采用用户主观感受时间的定义。
|
||||
|
||||
当然,我们在前端性能测试中,会利用一些事件的触发(比如DOM-Load、Page-load等)来客观地衡量“主观的前端性能”。这部分内容我会在后面介绍前端性能测试时,和你详细讨论。
|
||||
|
||||
## 系统吞吐量
|
||||
|
||||
系统吞吐量,是最能直接体现软件系统负载承受能力的指标。
|
||||
|
||||
这里需要注意的是,**所有对吞吐量的讨论都必须以“单位时间”作为基本前提**。其实,我认为把“Throughput”翻译成吞吐率更贴切,因为我们可以这样理解:吞吐率=吞吐量/单位时间。但既然国内很多资料已经翻译为了“吞吐量”,所以通常情况下我们不会刻意去区分吞吐量和吞吐率,统称为吞吐量。
|
||||
|
||||
对性能测试而言,通常用“Requests/Second”“Pages/Second”“Bytes/Second”来衡量吞吐量。当然,从业务的角度来讲,吞吐量也可以用单位时间的业务处理数量来衡量。
|
||||
|
||||
以不同方式表达的吞吐量可以说明不同层次的问题。比如:
|
||||
|
||||
- “Bytes/Second”和“Pages/Second”表示的吞吐量,主要受网络设置、服务器架构、应用服务器制约;
|
||||
- “Requests/Second”表示的吞吐量,主要受应用服务器和应用本身实现的制约。
|
||||
|
||||
这里需要特别注意的是:虽说吞吐量可以反映服务器承受负载的情况,但在不同并发用户数的场景下,即使系统具有相近的吞吐量,但是得到的系统性能瓶颈也会相差甚远。
|
||||
|
||||
比如,某个测试场景中采用100个并发用户,每个用户每隔1秒发出一个Request,另外一个测试场景采用1000个并发用户,每个用户每隔10秒发出一个Request。显然这两个场景具有相同的吞吐量, 都是100 Requests/second,但是两种场景下的系统性能拐点肯定不同。因为,两个场景所占用的资源是不同的。
|
||||
|
||||
这就要求性能测试场景的指标,必然不是单个,需要根据实际情况组合并发用户数、响应时间这两个指标。
|
||||
|
||||
## 总结
|
||||
|
||||
作为性能测试系列的第一篇文章,我和你一起梳理了软件性能、软件性能测试相关的知识点,旨在你对加深软件性能指标的理解,为后续的性能测试实战打好基础。
|
||||
|
||||
首先,我从终端用户、系统运维人员、软件设计开发人员和性能测试人员,这四个维度介绍了软件系统的性能到底指的是什么:
|
||||
|
||||
- 终端用户希望自己的业务操作越快越好;
|
||||
- 系统运维人员追求系统整体的容量和稳定;
|
||||
- 开发人员以“性能工程”的视角关注实现过程的性能;
|
||||
- 性能测试人员需要全盘考量、各个击破。
|
||||
|
||||
然后,我介绍了软件性能的三个最常用的指标:并发用户数,响应时间,系统吞吐量:
|
||||
|
||||
- 并发用户数包含不同层面的含义,既可以指实际的并发用户数,也可以指服务器端的并发数量;
|
||||
- 响应时间也包含两层含义,技术层面的标准定义和基于用户主观感受时间的定义;
|
||||
- 系统吞吐量是最能直接体现软件系统承受负载能力的指标,但也必须和其他指标一起使用才能更好地说明问题。
|
||||
|
||||
## 思考题
|
||||
|
||||
系统吞吐量的表现形式有很多,比如“Requests/Second”“Pages/Second”“Bytes/Second”等,你在性能测试项目中,选择具体的系统吞吐量指标时,会考虑哪些因素呢?
|
||||
|
||||
欢迎你给我留言。
|
||||
|
||||
|
||||
235
极客时间专栏/软件测试52讲/性能测试篇/29 | 聊聊性能测试的基本方法与应用领域.md
Normal file
235
极客时间专栏/软件测试52讲/性能测试篇/29 | 聊聊性能测试的基本方法与应用领域.md
Normal file
@@ -0,0 +1,235 @@
|
||||
<audio id="audio" title="29 | 聊聊性能测试的基本方法与应用领域" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/9a/08/9aa7f04121f28c7192dcdc2e8778dd08.mp3"></audio>
|
||||
|
||||
你好,我是茹炳晟。今天我和你分享的主题是:聊聊性能测试的基本方法与应用领域。
|
||||
|
||||
在上一次分享[《带你一起解读不同视角的软件性能与性能指标》](https://time.geekbang.org/column/article/14577)这个主题时,我介绍了衡量软件性能的三个最主要的指标:并发用户数、响应时间和系统吞吐量,和你分享了这个指标的内涵和外延。
|
||||
|
||||
所以,今天我会先继续上次的话题,和你分享并发用户数、响应时间和系统吞吐量这三个指标之间的关系和约束;然后,我会再和你分享性能测试七种常用方法,以及四大应用领域。
|
||||
|
||||
由于性能测试是一个很宽泛的话题,所以不同的人对性能测试的看法也不完全一样,同样一种方法可能也会有不同的表述方式。但是,从我亲身经历的实践来看,我们最关键的还是要去理解这些方法的本质和内涵,这样在面对实际问题时才能处变不惊,灵活应对。
|
||||
|
||||
虽然关于概念、方法和原理的内容会有些枯燥,但是掌握了这些看似枯燥的内容后,你会发现自己的性能测试知识体系越发完善了。当然,在这些看似枯燥的理论讲解中,我也会通过类比的方式,帮助你理解。如果你觉得不过瘾,还想知道一些更细节的实现,欢迎你给我留言,我们一起来讨论。
|
||||
|
||||
## 并发用户数、响应时间、系统吞吐量之间的关系
|
||||
|
||||
并发用户数、响应时间、系统吞吐量,这三个名词的含义可能就已经让你感觉云里雾里了,因此我会通过一个我们日常生活中的体检为例,再来解释一下它们到底是什么,以及它们之间的关系和约束。
|
||||
|
||||
你先来想象这样一个场景:假设你找了一份新工作,入职前需要到体检中心完成入职体检。
|
||||
|
||||
在体检中心做检查的过程,通常是先到前台登记个人信息并领取体检单,然后根据体检单的检查项目依次完成不同科室的检查。
|
||||
|
||||
假设一共有5个科室,每个科室有3个候诊室,你发现体检中心有很多人都在做检查,那么你一般会选择先做排队人数较少的检查项目,直至完成5个科室的全部检查,最后离开体检中心。
|
||||
|
||||
现在,我们做个类比:把整个体检中心想象成一个软件系统,从你进入体检中心到完成全部检查离开所花费的时间就是响应时间,而同时在体检中心参加体检的总人数就是并发用户数,那么系统吞吐量就可以想象成是单位时间内完成体检的人数,比如每小时100人。
|
||||
|
||||
如果你到达体检中心的时间比较早,这时人还很少,5个科室都不用排队,那么你就能以最短的时间完成体检。
|
||||
|
||||
也就是说,当系统的并发用户数比较少时,响应时间就比较短;但是由于整体的并发用户数少,所以系统的吞吐量也很低。从中,我们可以得出这样的结论:
|
||||
|
||||
>
|
||||
当系统并发用户数较少时,系统的吞吐量也低,系统处于空闲状态,我们往往把这个阶段称为 “空闲区间”。
|
||||
|
||||
|
||||
如果你到达体检中心时,这里的人已经比较多了,只有部分科室不需要排队,但好在每个科室都有3个候诊室同时进行检查,所以排队时间不会很长,你还是可以在较短的时间完成体检。
|
||||
|
||||
也就是说,当系统的并发用户数比较多时,响应时间不会增加太多,因此系统的整体吞吐量也随着并发用户数的变大而变大的。从中,我们可以得出这样的结论:
|
||||
|
||||
>
|
||||
当系统整体负载并不是很大时,随着系统并发用户数的增长,系统的吞吐量也会随之呈线性增长,我们往往把这个阶段称为 “线性增长区间”。
|
||||
|
||||
|
||||
但是,当体检中心的人越来越多时,每个科室都需要排队,而且每个科室的队伍都很长,你每检查完一个项目都要花很长时间去排队进行下一个检查项目。这样一来,你完成体检的时间就会明显变长。
|
||||
|
||||
也就是说,系统的并发用户数达到一定规模时,每个用户的响应时间都会明显变长,所以系统的整体吞吐量并不会继续随着并发用户数的增长而增长。从中,我们可以得出这样的结论:
|
||||
|
||||
>
|
||||
随着系统并发用户数的进一步增长,系统的处理能力逐渐趋于饱和,因此每个用户的响应时间会逐渐变长。相应地,系统的整体吞吐量并不会随着并发用户数的增长而继续呈线性增长。我们往往把这个阶段称为系统的“拐点”。
|
||||
|
||||
|
||||
最糟糕的情况来了,如果体检中心的人继续增加,你会发现连排队、站人的地方都没有了,所有人都被堵在了一起,候诊室中检查完的人出不来,排队的人又进不去。
|
||||
|
||||
也就是说,系统的并发用户数已经突破极限,每个用户的响应时间变得无限长,因此系统的整体吞吐量变成了零。换言之,此时的系统已经被压垮了。从中,我们可以得出这样的结论:
|
||||
|
||||
>
|
||||
随着系统并发用户数的增长,系统处理能力达到过饱和状态。此时,如果继续增加并发用户数,最终所有用户的响应时间会变得无限长。相应地,系统的整体吞吐量会降为零,系统处于被压垮的状态。我们往往把这个阶段称为“过饱和区间”。
|
||||
|
||||
|
||||
通过这个类比,相信你已经对并发用户数、响应时间和系统吞吐量理解得更透彻了,对于它们之间的关系和约束,也都了然于胸了。
|
||||
|
||||
只有理解了这些主要性能指标之间的约束关系,我们才能在实际的性能测试实践中设计有的放矢的性能测试场景。比如,后端性能测试的测试负载,我们一般只会把它设计在“线性增长区间”内;而压力测试的测试负载,我们则会将它设计在系统“拐点”上下,甚至是“过饱和区间”。
|
||||
|
||||
那么,接下来让我们一起来看一下性能测试的方法都有哪些。
|
||||
|
||||
## 常用的七种性能测试方法
|
||||
|
||||
根据在实际项目中的实践经验,我把常用的性能测试方法分为七大类:后端性能测试(Back-end Performance Test)、前端性能测试(Front-end Performance Test)、代码级性能测试(Code-level Performance Test)、压力测试(Load/Stress Test)、配置测试(Configuration Test)、并发测试(Concurrence Test),以及可靠性测试(Reliability Test)。接下来,我将详细为你介绍每一种测试方法。
|
||||
|
||||
**第一,后端性能测试**
|
||||
|
||||
其实,你平时听到的性能测试,大多数情况下指的是后端性能测试,也就是服务器端性能测试。
|
||||
|
||||
**后端性能测试,是通过性能测试工具模拟大量的并发用户请求,然后获取系统性能的各项指标,并且验证各项指标是否符合预期的性能需求的测试手段。**
|
||||
|
||||
这里的性能指标,除了包括并发用户数、响应时间和系统吞吐量外,还应该包括各类资源的使用率,比如系统级别的CPU占用率、内存使用率、磁盘I/O和网络I/O等,再比如应用级别以及JVM级别的各类资源使用率指标等。
|
||||
|
||||
由于需要模拟的并发用户数,通常在“几百”到“几百万”的数量级,所以你选择的性能测试工具,一定不是基于GUI的,而是要采用基于协议的模拟方式,也就是去模拟用户在GUI操作的过程中实际向后端服务发起的请求。
|
||||
|
||||
只有这样才能模拟很高的并发用户数,尽可能地模拟出真实的使用场景,这也是现在所有后端性能测试工具所采用的方法。
|
||||
|
||||
根据应用领域的不同,后端性能测试的场景设计主要包括以下两种方式:
|
||||
|
||||
- 基于性能需求目标的测试验证;
|
||||
- 探索系统的容量,并验证系统容量的可扩展性
|
||||
|
||||
**第二,前端性能测试**
|
||||
|
||||
前端性能测试并没有一个严格的定义和标准。
|
||||
|
||||
**通常来讲,前端性能关注的是浏览器端的页面渲染时间、资源加载顺序、请求数量、前端缓存使用情况、资源压缩等内容,希望借此找到页面加载过程中比较耗时的操作和资源,然后进行有针对性的优化,最终达到优化终端用户在浏览器端使用体验的目的。**
|
||||
|
||||
目前,业界普遍采用的前端测试方法,是雅虎(Yahoo)前端团队总结的7大类35条前端优化规则,你可以通过[雅虎网站](https://developer.yahoo.com/performance/rules.html?guccounter=1)查看这些规则,以及对各规则的详细解读。
|
||||
|
||||
我在这里列出了其中几个最典型也是最重要的规则,来帮助你理解前端性能测试优化的关注范围。
|
||||
|
||||
- **减少http请求次数**:http请求数量越多,执行过程耗时就越长,所以可以采用合并多个图片到一个图片文件的方法来减少http请求次数,也可以采用将多个脚本文件合并成单一文件的方式减少http请求次数;
|
||||
- **减少DNS查询次数**:DNS的作用是将URL转化为实际服务器主机IP地址,实现原理是分级查找,查找过程需要花费20~100ms的时间,所以一方面我们要加快单次查找的时间,另一方面也要减少一个页面中资源使用了多个不同域的情况;
|
||||
- **避免页面跳转**:页面跳转相当于又打开一个新的页面,耗费的时间就会比较长,所以要尽量避免使用页面跳转;
|
||||
- **使用内容分发网络(CDN)**:使用CDN相当于对静态内容做了缓存,并把缓存内容放在网络供应商(ISP)的机房,用户根据就近原则到ISP机房获取这些被缓存了的静态资源,因此可以大幅提高性能;
|
||||
- **Gzip压缩传输文件**:压缩可以帮助减小传输文件的大小,进而可以从网络传输时间的层面来减少响应时间;
|
||||
|
||||
**第三,代码级性能测试**
|
||||
|
||||
**代码级性能测试,是指在单元测试阶段就对代码的时间性能和空间性能进行必要的测试和评估,以防止底层代码的效率问题在项目后期才被发现的尴尬。**
|
||||
|
||||
如果你从事过性能测试相关的工作,一定遇到过这样的场景:系统级别的性能测试发现一个操作的响应时间很长,然后你要花费很多时间去逐级排查,最后却发现罪魁祸首是代码中某个实现低效的底层算法。这种自上而下的逐级排查定位的方法,效率通常都很低,代价也很高。
|
||||
|
||||
所以,我们就需要在项目早期,对一些关键算法进行代码级别的性能测试,以防止此类在代码层面就可以被发现的性能问题,遗留到最后的系统性能测试阶段才被发现。
|
||||
|
||||
但是,从实际执行的层面来讲,代码级性能测试并不存在严格意义上的测试工具,通常的做法是:改造现有的单元测试框架。
|
||||
|
||||
最常使用的改造方法是:
|
||||
|
||||
<li>
|
||||
将原本只会执行一次的单元测试用例连续执行n次,这个n的取值范围通常是2000~5000;
|
||||
</li>
|
||||
<li>
|
||||
统计执行n次的平均时间。如果这个平均时间比较长(也就是单次函数调用时间比较长)的话,比如已经达到了秒级,那么通常情况下这个被测函数的实现逻辑一定需要优化。
|
||||
</li>
|
||||
|
||||
这里之所以采用执行n次的方式,是因为函数执行时间往往是毫秒级的,单次执行的误差会比较大,所以采用多次执行取平均值的做法。
|
||||
|
||||
**第四,压力测试**
|
||||
|
||||
**压力测试,通常指的是后端压力测试**,一般采用后端性能测试的方法,不断对系统施加压力,并验证系统化处于或长期处于临界饱和阶段的稳定性以及性能指标,并试图找到系统处于临界状态时的主要瓶颈点。所以,压力测试往往被用于系统容量规划的测试。
|
||||
|
||||
还有些情况,在执行压力测试时,我们还会故意在临界饱和状态的基础上继续施加压力,直至系统完全瘫痪,观察这个期间系统的行为;然后,逐渐减小压力,观察瘫痪的系统是否可以自愈。
|
||||
|
||||
**第五,配置测试**
|
||||
|
||||
配置测试,主要用于观察系统在不同配置下的性能表现,通常使用后端性能测试的方法:
|
||||
|
||||
<li>
|
||||
通过性能基准测试(Performance Benchmark)建立性能基线(Performance Baseline);
|
||||
</li>
|
||||
<li>
|
||||
在此基础上,调整配置;
|
||||
</li>
|
||||
<li>
|
||||
基于同样的性能基准测试,观察不同配置条件下系统性能的差异,根本目的是要找到特定压力模式下的最佳配置。
|
||||
</li>
|
||||
|
||||
这里需要注意的是,“配置”是一个广义配置的概念,包含了以下多个层面的配置:
|
||||
|
||||
- 宿主操作系统的配置;
|
||||
- 应用服务器的配置;
|
||||
- 数据库的配置;
|
||||
- JVM的配置;
|
||||
- 网络环境的配置;
|
||||
- …
|
||||
|
||||
**第六,并发测试**
|
||||
|
||||
并发测试,指的是在同一时间,同时调用后端服务,期间观察被调用服务在并发情况下的行为表现,旨在发现诸如资源竞争、资源死锁之类的问题。
|
||||
|
||||
谈到并发测试,我就不得不和你说说“集合点并发”的概念了,它源于HP的LoadRunner,目前已经被广泛使用了。那,到底什么是“集合点并发”呢?
|
||||
|
||||
假设我们希望后端调用的并发数是100,如果直接设定100个并发用户是无法达到这个目标的,因为这100个并发用户会各自执行各自的操作,你无法控制某一个确定的时间点上后端服务的并发数量。
|
||||
|
||||
为了达到准确控制后端服务并发数的目的,我们需要让某些并发用户到达该集合点时,先处于等待状态,直到参与该集合的全部并发用户都到达时,再一起向后端服务发起请求。简单地说,就是先到的并发用户要等着,等所有并发用户都到了以后,再集中向后端服务发起请求。
|
||||
|
||||
比如,当要求的集合点并发数是100时,那么前99个到达的用户都会等在那里,直到第100个用户到了,才集中向后端服务发起请求。当然,实际达到服务器的并发请求数,还会因为网络延迟等原因小于100。
|
||||
|
||||
所以,**在实际项目中,我建议在要求的并发数上进行适当放大,比如要求的并发数是100,那我们集合点并发数可以设置为120。**
|
||||
|
||||
**第七,可靠性测试**
|
||||
|
||||
可靠性测试,是验证系统在常规负载模式下长期运行的稳定性。
|
||||
|
||||
**虽然可靠性测试在不同公司的叫法不同,但其本质就是通过长时间模拟真实的系统负载来发现系统潜在的内存泄漏、链接池回收等问题**。
|
||||
|
||||
由于真实环境下的实际负载,会有高峰和低谷的交替变化(比如,对于企业级应用,白天通常是高峰时段,而晚上则是低峰时段),所以为了尽可能地模拟出真实的负载情况,我们会每12小时模拟一个高峰负载,两个高峰负载中间会模拟一个低峰负载,依次循环3-7天,形成一个类似于“波浪形”的系统测试负载曲线。
|
||||
|
||||
然后,用这个“波浪形”的测试负载模拟真实的系统负载,完成可靠性测试。同样地,可靠性测试也会持续3-7天。
|
||||
|
||||
聊完了常用性能测试方法的种类后,我们再来简单看一下性能测试的四大应用领域,以及每个应用领域都会使用哪些性能测试方法。
|
||||
|
||||
## 性能测试的四大应用领域
|
||||
|
||||
不同的性能测试方法适用于不同的应用领域去解决不同的问题,这里“不同的应用领域”主要包括能力验证、能力规划、性能调优、缺陷发现这四大方面。每个应用领域可以根据自身特点,选择合适的测试方法。
|
||||
|
||||
**第一,能力验证**
|
||||
|
||||
能力验证是最常用,也是最容易理解的性能测试的应用领域,主要是验证“某系统能否在A条件下具有B能力”,通常要求在明确的软硬件环境下,根据明确的系统性能需求设计测试方案和用例。
|
||||
|
||||
能力验证这个领域最常使用的测试方法,包括后端性能测试、压力测试和可靠性测试。
|
||||
|
||||
**第二,能力规划**
|
||||
|
||||
能力规划关注的是,如何才能使系统达到要求的性能和容量。通常情况下,我们会采用探索性测试的方式来了解系统的能力。
|
||||
|
||||
能力规划解决的问题,主要包括以下几个方面:
|
||||
|
||||
- 能否支持未来一段时间内的用户增长;
|
||||
- 应该如何调整系统配置,使系统能够满足不断增长的用户数需求;
|
||||
- 应用集群的可扩展性验证,以及寻找集群扩展的瓶颈点;
|
||||
- 数据库集群的可扩展性验证;
|
||||
- 缓存集群的可扩展性验证;
|
||||
- …
|
||||
|
||||
能力规划最常使用的测试方法,主要有后端性能测试、压力测试、配置测试和可靠性测试。
|
||||
|
||||
**第三,性能调优**
|
||||
|
||||
性能调优,其实是性能测试的延伸。在一些大型软件公司,会有专门的性能工程(Performance Engineering)团队,除了负责性能测试的工作外,还会负责性能调优。
|
||||
|
||||
性能调优主要解决性能测试过程中发现的性能瓶颈的问题,通常会涉及多个层面的调整,包括硬件设备选型、操作系统配置、应用系统配置、数据库配置和应用代码实现的优化等等。
|
||||
|
||||
这个领域最常用的测试方法,涵盖了我在上面分享的七大类测试方法,即后端性能测试、前端性能测试、代码级性能测试、压力测试、配置测试、并发测试和可靠性测试。
|
||||
|
||||
**第四,缺陷发现**
|
||||
|
||||
缺陷发现,是一个比较直接的应用领域,通过性能测试的各种方法来发现诸如内存泄露、资源竞争、不合理的线程锁和死锁等问题。
|
||||
|
||||
缺陷发现,最常用的测试方法主要有并发测试、压力测试、后端性能测试和代码级性能测试。
|
||||
|
||||
上面这些内容就是性能测试的常用方法和应用领域了,我用一张表汇总了各个应用领域需要用到的测试方法,希望可以帮助你记忆、理解。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/18/ba/18ee2034c4bd8b08fc959b9bc4ffa7ba.png" alt="">
|
||||
|
||||
## 总结
|
||||
|
||||
今天我通过一个生活中“体检”的实例,和你分享了并发用户数、响应时间和系统吞吐量三者之间的关系:
|
||||
|
||||
- 当系统整体负载并不是很大时,随着并发用户数的增长,系统的吞吐量也会随之线性增长;
|
||||
- 随着并发用户数的进一步增长,系统处理能力逐渐趋于饱和,因此每个用户的响应时间会逐渐变长,相应地,系统的整体吞吐量并不会随着并发用户数的增长而继续线性增长。
|
||||
- 如果并发用户数再继续增长,系统处理能力达到过饱和状态,此时所有用户的响应时间会变得无限长,相应地,系统的整体吞吐量会降为零,系统处于被压垮的状态。
|
||||
|
||||
然后,我跟你分享了后端性能测试、前端性能测试、代码级性能测试、压力测试、配置测试、并发测试,以及可靠性测试这七种常用的性能测试方法,并探讨了这七种方法在能力验证、能力规划、性能调优和缺陷发现这四种场景下的使用情况。
|
||||
|
||||
希望我今天的分享,可以帮你打好性能测试知识体系的基础,解决你在实际项目中遇到的问题。
|
||||
|
||||
## 思考题
|
||||
|
||||
我今天提到的性能测试的七种测试方法,以及四大应用领域,你在实际的工程项目中接触过哪些呢?在使用过程中,你有没有遇到过什么问题,又是如何解决的?
|
||||
|
||||
感谢你的收听,欢迎给我留言。
|
||||
161
极客时间专栏/软件测试52讲/性能测试篇/30 | 工欲善其事必先利其器:后端性能测试工具原理与行业常用工具简介.md
Normal file
161
极客时间专栏/软件测试52讲/性能测试篇/30 | 工欲善其事必先利其器:后端性能测试工具原理与行业常用工具简介.md
Normal file
@@ -0,0 +1,161 @@
|
||||
<audio id="audio" title="30 | 工欲善其事必先利其器:后端性能测试工具原理与行业常用工具简介" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/ec/3d/ece97df96e76f3939504d09d2b6f143d.mp3"></audio>
|
||||
|
||||
你好,我是茹炳晟。今天我和你分享的主题是:工欲善其事必先利其器之后端性能测试工具原理与行业常用工具简介。
|
||||
|
||||
我在《聊聊性能测试的基本方法与应用领域》这个主题里介绍了七种测试方法,但不管是什么类型的性能测试方法,都需要去模拟大量并发用户的同时执行,所以性能测试基本都是靠工具实现。没有工具,性能测试将寸步难行。
|
||||
|
||||
所以,我今天就从后端性能测试的工具讲起,和你一起讨论它们的实现原理,以及如何用于后端的性能测试。另外,我还会和你分享一些中大型互联网企业选择的性能测试工具。
|
||||
|
||||
由于我今天要分享的知识点比较多,而且是相对独立的,所以我会采用问答的形式展开这些内容。我希望通过今天的分享,你能够对以下的问题和知识点有完整、清晰的理解与认识:
|
||||
|
||||
- 后端性能测试和后端性能测试工具之间的关系是什么?
|
||||
- 后端性能测试工具和GUI自动化测试工具最大的区别是什么?
|
||||
- 后端性能测试工具的原理是什么?
|
||||
- 后端性能测试中,性能测试场景设计是什么意思,具体会涉及哪些内容?
|
||||
- 业内主流的后端性能测试工具有哪些?
|
||||
|
||||
## 后端性能测试和后端性能测试工具之间的关系是什么?
|
||||
|
||||
后端性能测试工具是实现后端性能测试的技术手段,但是千万不要简单地把使用后端性能测试工具等同于后端性能测试,它只是后端性能测试中的一个必要步骤而已。
|
||||
|
||||
**完整的后端性能测试应该包括性能需求获取、性能场景设计、性能测试脚本开发、性能场景实现、性能测试执行、性能结果报告分析、性能优化和再验证。**
|
||||
|
||||
在这其中,后端性能测试工具主要在性能测试脚本开发、性能场景实现、性能测试执行这三个步骤中发挥作用,而其他环节都要依靠性能测试工程师的专业知识完成。
|
||||
|
||||
是不是感觉有点抽象,难以理解呢?我来做个类比吧。
|
||||
|
||||
假如你现在要去医院看病,医生会根据你对身体不适的描述,要求你先去验血,并确定需要检查的血液指标。验血是通过专业的医疗仪器分析你的血样,并得到验血报告。
|
||||
|
||||
医生拿到验血报告后,根据常年积累的专业知识,然后结合验血报告的各项指标以及指标之间的相互关系判断你的病情,并给出诊断结果以及相应的治疗措施。
|
||||
|
||||
同样的验血报告,如果给不懂医术的人看,就是一堆没有意义的数据;如果给一个初级医生看,他可能只能基于单个指标的高低给出可能的推测;但是,如果是给一个具有丰富临床经验的医生看,他往往可以根据这些指标以及它们之间的相互关系给出很明确的诊断结果。
|
||||
|
||||
现在,我把这个过程和性能测试做个类比,把性能测试对应到整个看病的过程:
|
||||
|
||||
- 需求获取对应的是你向医生描述身体不适细节的过程,医生需要知道要帮你解决什么问题;
|
||||
- 设计性能场景对应的是医生决定需要检查哪些血液指标的过程;
|
||||
- 使用性能测试工具对应的是使用医疗仪器分析血样的过程;
|
||||
- 性能测试报告对应的就是验血报告;
|
||||
- 性能测试人员分析性能结果报告的过程,对应的是医生解读验血报告的过程;
|
||||
- 性能测试人员根据性能报告进行性能优化的过程,对应的是医生根据验血报告判断你的病情,并给出相应治疗措施的过程。
|
||||
|
||||
所以,在我看来**使用性能测试工具获得性能测试报告只是性能测试过程中的一个必要步骤而已,而得出报告的目的是让性能测试工程师去做进一步的分析,以得出最终结论,并给出性能优化的措施。**
|
||||
|
||||
## 后端性能测试工具和GUI自动化测试工具最大的区别是什么?
|
||||
|
||||
虽然后端性能测试工具和GUI自动化测试工具都是通过自动化的手段模拟终端用户使用系统的行为,但是两者实现的原理截然不同。
|
||||
|
||||
**第一个显著区别是,模拟用户行为的方式。**
|
||||
|
||||
GUI自动化测试工具模拟的是用户的界面操作,因此测试脚本记录的是用户在界面上对控件的操作;而性能测试工具模拟的是用户的客户端与服务器之间的通信协议和数据,这些通信协议和数据往往是用户在界面上执行GUI操作时产生的。
|
||||
|
||||
明白了这一点,你自然就能明白为什么录制虚拟用户性能测试脚本时,我们需要先选定录制协议了。
|
||||
|
||||
另外,正是由于脚本的模拟是基于协议的,所以我们才能比较方便地模拟成千上万并发用户同时使用系统的场景;否则,如果性能测试基于GUI发起,那我们就需要成千上万的浏览器同时执行用例,而这显然是不可能的。
|
||||
|
||||
**第二个显著的区别是,测试的执行方式。**
|
||||
|
||||
GUI自动化测试的执行,一般是单用户执行并验证功能结果;而性能测试的执行,往往需要同时模拟大量的并发用户,不仅需要验证业务功能是否成功完成,还要收集各种性能监控指标,会涉及到压力产生器、并发用户调度控制、实时监控收集等内容,所以性能测试的执行控制要比GUI自动化测试复杂得多。
|
||||
|
||||
这部分内容,我稍后在第32和33这两篇文章中详细展开。
|
||||
|
||||
## 后端性能测试工具的原理是什么?
|
||||
|
||||
虽然后端性能测试工具种类很多,但是由于都不能通过GUI的方式来模拟并发,所以其基本原理和主要概念基本一致。
|
||||
|
||||
**首先,后端性能测试工具会基于客户端与服务器端的通信协议,构建模拟业务操作的虚拟用户脚本**。对于目前主流的Web应用,通常是基于HTTP/HTTPS协议;对于Web Service应用,是基于Web Service协议;至于具体基于哪种协议,你需要和开发人员或者架构师确认,当然现在有些后端性能测试工具也可以直接帮你检测协议的种类。
|
||||
|
||||
我们把这些基于协议模拟用户行为的脚本称为虚拟用户脚本,而把开发和产生这些脚本的工具称为**虚拟用户脚本生成器**。
|
||||
|
||||
不同后端性能测试工具的虚拟用户脚本生成器,在使用上的区别比较大:比如,LoadRunner是通过录制后再修改的方式生成虚拟用户脚本;而JMeter主要是通过添加各种组件,然后对组件进行配置的方式生成虚拟用户脚本。
|
||||
|
||||
虽然LoadRunner也支持采用直接开发的方式产生虚拟用户脚本,但是因为开发难度太大,所以基本上都是采用先录制再开发的方式,不会直接去开发。另外,虽然JMeter也支持录制,但是JMeter的录制功能是通过设置代理完成的,而且录制出来的脚本都是原始的http请求,并没有经过适当的封装,所以录制功能比较弱。
|
||||
|
||||
虽然不同工具的使用方式各有特色,但其本质上都是通过协议模拟用户的行为。
|
||||
|
||||
**然后,开发完成了虚拟用户脚本之后,后端性能测试工具会以多线程或多进程的方式并发执行虚拟用户脚本,来模拟大量并发用户的同时访问,从而对服务器施加测试负载。**
|
||||
|
||||
其中,我们把实际发起测试负载的机器称为**压力产生器**。受限于CPU、内存,以及网络带宽等硬件资源,一台压力产生器能够承载的虚拟用户数量是有限的,当需要发起的并发用户数量超过了单台压力产生器能够提供的极限时,就需要引入多台压力产生器合作发起需要的测试负载。
|
||||
|
||||
一旦有了多台压力产生器,那就需要一个专门的控制器来统一管理与协调这些压力产生器,我们把这个专门的控制器称为**压力控制器**。压力控制器会根据性能测试场景的设计,来控制和协调多台压力产生器上的多线程或多进程执行的虚拟用户脚本,最终模拟出性能测试场景中的测试负载。
|
||||
|
||||
**接着,在施加测试负载的整个过程中,后端性能测试工具除了需要监控和收集被测系统的各种性能数据以外,还需要监控被测系统各个服务器的各种软硬件资源**。比如,后端性能测试工具需要监控应用服务器、数据库服务器、消息队列服务器、缓存服务器等各种资源的占用率。我们通常把完成监控和数据收集的模块称为**系统监控器**。
|
||||
|
||||
在性能测试执行过程中,系统监控器的数据显示界面是性能测试工程师最密切关注的部分,性能测试工程师会根据实时的数据显示来判断测试负载情况下的系统健康状况。
|
||||
|
||||
不同的后端测试工具中,系统监控器能力差别也比较大。比如,LoadRunner的系统监控器就很强大,支持收集各种操作系统的系统参数,还支持与SiteScope等第三方专业监控工具的无缝集成。
|
||||
|
||||
**最后,测试执行完成后,后端性能测试工具会将系统监控器收集的所有信息汇总为完整测试报告**,后端性能测试工具通常能够基于该报告生成各类指标的各种图表,还能将多个指标关联在一起进行综合分析来找出各个指标之间的关联性。我们把完成这部分工作的模块称为**测试结果分析器**。
|
||||
|
||||
需要强调的是,测试结果分析器只是按需提供多种不同维度和表现形式的数据展现工作,而对数据的分析工作,还是要依赖于具有丰富经验的性能测试工程师。
|
||||
|
||||
## 后端性能测试场景设计是什么意思,具体会涉及哪些内容?
|
||||
|
||||
性能测试场景设计,是后端性能测试中的重要概念,也是压力控制器发起测试负载的依据。
|
||||
|
||||
性能测试场景设计,目的是要描述性能测试过程中所有与测试负载以及监控相关的内容。通常来讲,性能测试场景设计主要会涉及以下部分:
|
||||
|
||||
- 并发用户数是多少?
|
||||
- 测试刚开始时,以什么样的速率来添加并发用户?比如,每秒增加5个并发用户。
|
||||
- 达到最大并发用户数后持续多长时间?
|
||||
- 测试结束时,以什么样的速率来减少并发用户?比如,每秒减少5个并发用户。
|
||||
- 需要包含哪些业务操作,各个业务操作的占比是多少?比如,10%的用户在做登录操作,70%的用户在做查询操作,其他20%的用户在做订单操作。
|
||||
- 一轮虚拟用户脚本执行结束后,需要等待多长时间开始下一次执行?
|
||||
- 同一虚拟用户脚本中,各个操作之间的等待时间是多少?
|
||||
- 需要监控哪些被测服务器的哪些指标?
|
||||
- 脚本出错时的处理方式是什么?比如,错误率达到10%时,自动停止该脚本。
|
||||
- 需要使用多少台压力产生器?
|
||||
|
||||
以上这些场景组合在一起,就构成了性能测试场景设计的主要内容。也就是说,性能测试场景会对测试负载组成、负载策略、资源监控范围定义、终止方式,以及负载产生规划作出定义,而其中的每一项还会包含更多的内容。具体请参见如图1所示的思维导图。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/4f/02/4f4f3d91ba710fe1f39cac341d296402.png" alt="" />
|
||||
|
||||
## 业内主流的后端性能测试工具有哪些?
|
||||
|
||||
目前,业内有很多成熟的后端性能测试工具,比如传统的LoadRunner、JMeter、NeoLoad等。另外,现在还有很多云端部署的后端性能测试工具或平台,比如CloudTest、Loadstorm、阿里的PTS等。
|
||||
|
||||
其中,最为常用的商业工具是HP软件(现在已经被Micro Focus收购)的LoadRunner,由于其强大的功能和广泛的协议支持,几乎已经成了性能测试工具的代名词。大量的传统软件企业,也基本都使用LoadRunner实施性能测试,所以我在后面分享企业级服务器端性能测试的实践时,也是以LoadRunner为基础展开的。
|
||||
|
||||
另外,JMeter是目前开源领域最主流的性能测试工具。JMeter的功能非常灵活,能够支持HTTP、FTP、数据库的性能测试,也能够充当HTTP代理来录制浏览器的HTTP请求,还可以根据Apache等Web服务器的日志文件回放HTTP流量,还可以通过扩展支持海量的并发。
|
||||
|
||||
然后,再加上JMeter开源免费的特点,已经被很多互联网企业广泛应用。比如,饿了么就是使用JMeter来完成系统的全链路压力测试。
|
||||
|
||||
其实,传统软件企业偏向于使用LoadRunner,而互联网企业普遍采用JMeter,是有原因的。
|
||||
|
||||
LoadRunner License是按照并发用户数收费的,并发用户数越高收费也越贵,但是LoadRunner的脚本开发功能、执行控制、系统监控以及报告功能都非常强大,易学易用。
|
||||
|
||||
而传统软件企业,需要测试的并发用户数并不会太高,通常是在几百到十几万这个数量级,而且它们很在意软件的易用性和官方支持能力,所以往往热衷于直接选择成熟的商业工具LoadRunner。
|
||||
|
||||
但是,互联网企业的并发用户请求数量很高,很多软件都会达到百万,甚至是千万的级别。那么,如果使用LoadRunner的话:
|
||||
|
||||
<li>
|
||||
费用会高的离谱;
|
||||
</li>
|
||||
<li>
|
||||
LoadRunner对海量并发的测试支持并不太好;
|
||||
</li>
|
||||
<li>
|
||||
很多互联网企业还会有特定的工具需求,这些特定的需求很难在LoadRunner中实现,而在开源的JMeter中,用户完全可以根据需求进行扩展。
|
||||
</li>
|
||||
|
||||
所以互联网企业往往选用JMeter方案,而且通常会自己维护扩展版本。
|
||||
|
||||
## 总结
|
||||
|
||||
今天,我以问答的形式,和你分享了后端性能测试的理论,以及工具使用的问题。
|
||||
|
||||
首先,我和你解释了后端性能测试和后端性能测试工具之间的关系。在我看来使用性能测试工具获得性能测试报告,只是性能测试过程中的一个必要步骤而已,而得出报告的目的是让性能测试工程师去分析并给出性能优化的措施。
|
||||
|
||||
然后,我解释了后端性能测试工具和GUI自动化测试工具最大的区别,即它们模拟用户行为的方式以及测试的执行方式不同。
|
||||
|
||||
接着,我介绍了后端性能测试工具的基本原理。它首先通过虚拟用户脚本生成器生成虚拟用户脚本;然后根据性能测试场景设计的要求,通过压力控制器控制协调各个压力产生器以并发的方式执行虚拟用户脚本;同时,在测试执行过程中,通过系统监控器收集各种性能指标以及系统资源占用率;最后,通过测试结果分析器展示测试结果数据。
|
||||
|
||||
最后,我介绍了性能测试场景设计,并分析了业内主流的后端性能测试工具LoadRunner和JMeter,以及传统软件企业和互联网企业在选择后端性能测试工具时的考量。
|
||||
|
||||
## 思考题
|
||||
|
||||
除了我今天提到的后端性能测试工具外,你还接触过哪些后端性能测试工具?这些后端性能测试工具中又有哪些好的设计呢?
|
||||
|
||||
感谢你的收听,欢迎你给我留言。
|
||||
|
||||
|
||||
198
极客时间专栏/软件测试52讲/性能测试篇/31 | 工欲善其事必先利其器:前端性能测试工具原理与行业常用工具简介.md
Normal file
198
极客时间专栏/软件测试52讲/性能测试篇/31 | 工欲善其事必先利其器:前端性能测试工具原理与行业常用工具简介.md
Normal file
@@ -0,0 +1,198 @@
|
||||
<audio id="audio" title="31 | 工欲善其事必先利其器:前端性能测试工具原理与行业常用工具简介" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/bd/b0/bda18628bd753eb756f42518da61c0b0.mp3"></audio>
|
||||
|
||||
你好,我是茹炳晟。今天我和你分享的主题是:工欲善其事必先利其器之前端性能测试工具原理与行业常用工具简介”。
|
||||
|
||||
不同于后端性能测试知识的琐碎、独立,今天我将从问答形式回到正常的分享思路上,为你介绍前端性能测试工具为。我会以一个具体网站为例,和你分析WebPagetest的用法,以及前端性能相关的主要概念与指标。
|
||||
|
||||
## WebPagetest功能简介
|
||||
|
||||
WebPagetest,是前端性能测试的利器:
|
||||
|
||||
- 可以为我们提供全方位的量化指标,包括页面的加载时间、首字节时间、渲染开始时间、最早页面可交互时间、页面中各种资源的字节数、后端请求数量等一系列数据;
|
||||
- 还可以自动给出被测页面性能优化水平的评价指标,告诉我们哪些部分的性能已经做过优化处理了,哪些部分还需要改进;
|
||||
- 同时,还能提供Filmstrip视图、Waterfall视图、Connection视图、Request详情视图和页面加载视频慢动作。
|
||||
|
||||
可以说,WebPagetest为我们提供了前端页面性能测试所需要的一切,而且还是免费的。接下来,我们就通过测试一个具体的网站,实践一下它的强大功能,以及具体使用方法吧。
|
||||
|
||||
## 使用WebPagetest测试某网站的首页
|
||||
|
||||
那么,接下来我就以某网站首页的前端性能测试和评估为例,和你一起看看如何使用这个强大的前端性能工具。
|
||||
|
||||
**首先,访问WebPagetest的主页“[http://www.webpagetest.org/”](http://www.webpagetest.org/%E2%80%9D) ,也就是工具的使用界面。**
|
||||
|
||||
<li>
|
||||
将被测页面的地址填写到被测Website URL栏中;
|
||||
</li>
|
||||
<li>
|
||||
选择测试发起的地域(Test Location)以及你希望使用的浏览器,这里我选择了美国旧金山、Chrome浏览器。
|
||||
</li>
|
||||
|
||||
WebPagetest在全球各大洲的很多国家和地区都有自己的测试代理机,这些测试代理机可能是虚拟机,也可能是真机,还有很多是建立在Amazon EC2上的云端机器。另外,WebPagetest除了支持各种浏览器以外,还支持主流的Android设备和Apple设备。
|
||||
|
||||
**然后,选择需要模拟的网络情况**。这里我选择了有线网络Cable,当然你也可以根据你的测试要求选择各种3G或者4G移动网络。
|
||||
|
||||
**接着,在Repeat View中选择“First View and Repeat View”**。这是一个很关键的选项。我们知道当使用浏览器访问网站时,第一次打开一个新的网页往往会很慢,而第二次打开通常就会快很多,这是因为浏览器端会缓存很多资源。这个选项的意思就是既要测试第一次打开页面的前端性能(First View),也要测试在有缓存情况下重复打开的前端性能(Repeat View)。
|
||||
|
||||
**最后,点击“Start Test”发起测试**。最终的测试设置界面,如图1所示。由于全球所有的用户会共享这些散布在各地的测试代理机,所以发起测试后,一般情况下我们的测试并不会被立即执行,而是会进入排队系统。当然,WebPagetest界面会清楚地告诉你排在第几位。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/34/76/34dd44a44b1344dfa66ab9f4b6bb6276.png" alt="" />
|
||||
|
||||
测试执行完成后,我们会看到如图2所示的测试结果页面。这个页面包含非常多的信息,接下来我会一一解读这些信息,同时跟你分享前端性能指标相关的概念。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/6d/bd/6d886a2474f9dee528ee825574e601bd.png" alt="" />
|
||||
|
||||
## 前端性能评估结果评分
|
||||
|
||||
图2右上角的性能评估结果栏,列出了主要性能评估项目的评分。可以看到“First Byte Time”“Keep-alive Enabled”和“Compress Transfer”三项的评分都是A级,说明这三项做得比较好。但是,“Compress Images”“Cache static content”和“Effective use of CDN”的评分比较差,是需要优化的部分。
|
||||
|
||||
那么,接下来我们就看看这六项前端性能指标分别代表什么涵义。
|
||||
|
||||
**第一,First Byte Time**
|
||||
|
||||
First Byte Time,指的是用户发起页面请求到接收到服务器返回的第一个字节所花费的时间。这个指标反映了后端服务器处理请求、构建页面,并且通过网络返回所花费的时间。
|
||||
|
||||
本次测试的结果,首次打开页面(First View)花费的时间是999 ms,重复打开页面(Repeat View)花费的时间是860 ms。这两个指标都在1 s以下,所以WebPagetest给出了A级的评分。
|
||||
|
||||
**第二,Keep-alive Enabled**
|
||||
|
||||
页面上的各种资源(比如,图片、JavaScript、CSS等)都需要通过链接Web服务器来一一获取,与服务器建立新链接的过程往往比较耗费时间,所以理想的做法是尽可能重用已经建立好的链接,而避免每次使用都去创建新的链接。
|
||||
|
||||
Keep-alive Enabled就是,要求每次请求使用已经建立好的链接。它属于服务器上的配置,不需要对页面本身进行任何更改,启用了Keep-alive通常可以将加载页面的时间减少40%~50%,页面的请求数越多,能够节省的时间就越多。
|
||||
|
||||
如图3所示,本次测试的结果显示,所有的请求都复用了同一个链接,所以WebPagetest也给出了A级的评分。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/26/f5/267f522f142b768accbb0d7c5deacaf5.png" alt="" />
|
||||
|
||||
**第三,Compress Transfer**
|
||||
|
||||
如果将页面上的各种文本类的资源,比如Html、JavaScript、CSS等,进行压缩传输,将会减少网络传输的数据量,同时由于JavaScript和CSS都是页面上最先被加载的部分,所以减小这部分的数据量会加快页面的加载速度,同时也能缩短First Byte Time。
|
||||
|
||||
为文本资源启用压缩通常也是服务器配置更改,无需对页面本身进行任何更改。
|
||||
|
||||
如图4所示,本次测试结果显示,这个网站绝大多数的文本类资源都通过GZip进行了压缩,所以WebPagetest也给出了A级的评分。但是第13和第20项的两个资源并没有被压缩,报告中显示如果这两个资源也经过压缩,将可以减少额外的24.3KB的数据传输量。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/be/d5/be73f00359e0907b4a19c01bb11d9ed5.png" alt="" />
|
||||
|
||||
**第四,Compress Images**
|
||||
|
||||
为了减少需要网络传输的数据量,图像文件也需要进行压缩处理。显然本次测试结果显示(图5),所有的JPEG格式图片都没有经过必要的压缩处理,并且所有的JPEG格式图片都没有使用渐进式JPEG(Progressive JPEG)技术,所以WebPagetest给出了D级的评分。
|
||||
|
||||
如果你不是专门做前端的工程师,可能并不知道什么是渐进式JPEG,没关系,我来简单解释一下吧。
|
||||
|
||||
普通JPEG文件存储方式是按从上到下的扫描方式,把每一行顺序地保存在JPEG文件中。打开这个文件显示它的内容时,数据将按照存储时的顺序从上到下一行一行地被显示,直到所有的数据都被读完,就完成了整张图片的显示。
|
||||
|
||||
如果文件较大或者网络下载速度较慢,就会看到图片是被一行一行加载的。为了更好的用户体验,渐进式JPEG技术就出现了。
|
||||
|
||||
渐进式JPEG包含多次扫描,然后将扫描顺序存储在JPEG文件中。打开文件的过程,会先显示整个图片的模糊轮廓,随着扫描次数的增加,图片会变得越来越清晰。这种格式的主要优点是在网络较慢时,通过图片轮廓就可以知道正在加载的图片大概是什么。
|
||||
|
||||
所以,这种技术往往被一些网站用于打开较大图片。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/cb/4e/cbc6fe30d01bfe4051f2061f9bf12b4e.png" alt="" /><br />
|
||||
<img src="https://static001.geekbang.org/resource/image/ed/05/ed9f9ae7384b0839b44c1d31a4e11705.png" alt="" />
|
||||
|
||||
**第五,Cache Static Content**
|
||||
|
||||
一般情况下,页面上的静态资源不会经常变化,所以如果你的浏览器可以缓存这些资源,那么当重复访问这些页面时,就可以从缓存中直接使用已有的副本,而不需要每次向Web服务器请求资源。这种做法,可以显著提高重复访问页面的性能,并减少Web服务器的负载。
|
||||
|
||||
如图6所示,本次测试结果显示,被测网站有超过一半的静态资源没有被浏览器缓存,每次都需要从Web服务器端获取,所以WebPagetest给出了F级的评分。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/9d/e1/9d24087763ae50ea4ff90a1cd04b7be1.png" alt="" /><br />
|
||||
<img src="https://static001.geekbang.org/resource/image/bf/e8/bfcc9f3aaebd5ec59d711736823124e8.png" alt="" />
|
||||
|
||||
**第六,Effective use of CDN**
|
||||
|
||||
首先,我来解释一下什么是CDN。
|
||||
|
||||
CDN是内容分发网络的缩写,其基本原理是采用各种缓存服务器,将这些缓存服务器分布到用户访问相对集中的地区的网络供应商机房内,当用户访问网站时,利用全局负载技术将用户的访问指向距离最近的、工作正常的缓存服务器上,由缓存服务器直接响应用户请求。
|
||||
|
||||
理解了什么是CDN后,我们再一起来看一下本次测试中CDN的使用情况。如图7所示,显然本次被测网站绝大多数的资源并没使用CDN。也许是由于本次发起测试的机器是在美国旧金山,而旧金山可能并不是该网站的目标市场,所以它并没有在这里的CDN上部署资源。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/7b/15/7b7522032fa4996f7c2f76f63c4c1815.png" alt="" />
|
||||
|
||||
## 其他前端性能指标解读
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/22/c9/228e66ac2fa08026bfaeb3defff139c9.png" alt="" />
|
||||
|
||||
现在,我们再回过头来看看如图8所示的表格,这个表格包含了很多的前端性能指标,大多数指标,我们可以从字面上很容易理解其含义,比如Load Time、First Byte、Requests等,我就不再赘述了。
|
||||
|
||||
但是,Start Render、First Interactive和Speed Index这三个指标,相对较难理解,所以我会简单为你解释一下。
|
||||
|
||||
**第一,Start Render**
|
||||
|
||||
Start Render,指的是浏览器开始渲染的时间,从用户角度看就是在页面上看到第一个内容的时间。该时间决定了用户对页面加载快慢的的第一直观印象,这个时间越短用户会感觉页面速度越快,这样用户也会有耐心去等待其他内容的展现。如果这个时间过长,则用户会在长时间内面对一个空白页面后,失去耐心。
|
||||
|
||||
理论上讲,Start Render时间主要由三部分组成,分别是“发起请求到服务器返回第一个字节的时间(也就是First Byte时间)”“从服务器加载HTML文档的时间”,以及“HTML文档头部解析完成所需要的时间”,因此**影响Start Render时间的因素就包括服务器响应时间、网络传输时间、HTML文档的大小以及HTML头中的资源使用情况。**
|
||||
|
||||
本次测试中,第一次打开网页的Start Render时间是5 s,而第二次打开网页的Start Render时间是1.83 s。理想的Start Render时间并没有严格的标准,一般来情况下,这个值最好不要大于3 s,所以这个网站还可以再优化一下这个指标。
|
||||
|
||||
优化的基本思路是先找出时间到底花在了哪里,由于第二次的结果还是比较理想,所以可以从首次资源加载的角度找出突破口。
|
||||
|
||||
**第二,First Interactive**
|
||||
|
||||
First Interactive,可以简单地理解为最早的页面可交互时间。页面中可交互的内容,包括很多种类,比如点击一个链接、点击一个按钮都属于页面可交互的范畴。First Interactive时间的长短对用户体验的影响十分重要,决定着用户对页面功能的使用,这个值越短越好。
|
||||
|
||||
为了使这个值尽可能得小,我们通常会采取以下措施:
|
||||
|
||||
- 只有页面控件内容渲染出来了,才有可能进行交互,所以First Interactive依赖于Start Render时间。
|
||||
- 尽量将交互控件的代码放置在HTML BODY的前部,让其尽早加载。
|
||||
- 尽早做JavaScript的初始化和绑定,目前大多数做法有两种,一是在DOM Ready中做所有JavaScript的初始化和功能绑定,二是在页面底部做JavaScript的初始化和功能绑定。
|
||||
|
||||
这两种方式的优点在于简单,不需要关注具体DOM结点的位置;缺点则在于初始化的时间太晚。因此,**应该将JavaScript的初始化提前到相关DOM元素建立起来后进行,例如将初始化的操作直接放在元素之后进行,这样就可以使控件尽可能早地变成可交互状态。**
|
||||
|
||||
本次测试中,第一次打开网页的First Interactive时间是7.788 s,而第二次打开网页的First Interactive时间是略大于1.686 s的某个值。理想的First Interactive时间也没有严格的标准,一般情况下,这个值最好不要大于5 s,所以这个网站还可以根据上面的三条措施再优化一下这个指标。
|
||||
|
||||
**第三,Speed Index**
|
||||
|
||||
严格来说,Speed Index是通过微积分定义的。我们理解起来会比较困难,所以在这里我们和你只做定性的讨论。
|
||||
|
||||
通常,影响网页性能体验的一个重要指标是页面打开时间。打开时间越短,其体验越好。但是,当存在两个打开时间完全相同的网站A和B时,其中网站A的打开过程是逐渐渲染页面完成的,而网站B的打开过程则是空白了一段时间后在短时间内完成页面渲染完成的。
|
||||
|
||||
毫无疑问,网站A的用户体验一定好于B。Speed Index就是用来衡量这种体验的,通常来讲,它的值越小越好。
|
||||
|
||||
本次测试中,第一次打开网页的Speed Index是8036,而第二次打开网页的Speed Index是2373。
|
||||
|
||||
## WebPagetest实际使用中需要解决的问题
|
||||
|
||||
讨论到这里,你是不是觉得WebPagetest是一个很强大的免费工具,但是如果想要在实际工程项目中全面推行该工具的话,还需要解决两个问题。
|
||||
|
||||
**第一个问题是,如果被测网站部署在公司内部的网络中,那么处于外网的WebPagetest就无法访问这个网站,也就无法完成测试**。要解决这个问题,你需要在公司内网中搭建自己的私有WebPagetest以及相关的测试发起机。具体如何搭建,你可以参考[WebPagetest官网的建议](https://github.com/WPO-Foundation/webpagetest-docs/blob/master/user/Private%20Instances/README.md),这里我就不再继续展开了。
|
||||
|
||||
**第二个问题是,用WebPagetest执行前端测试时,所有的操作都是基于界面操作的,不利于与CI/CD的流水线集成**。要解决这个问题,就必须引入WebPagetest API Wrapper。
|
||||
|
||||
WebPagetest API Wrapper是一款基于Node.js,调用了WebPagetest提供的API的命令行工具。也就是说,你可以利用这个命令行工具发起基于WebPagetest的前端性能测试,这样就可以很方便地与CI/CD流水线集成了。具体的使用步骤如下:
|
||||
|
||||
<li>
|
||||
通过“npm install webpagetest -g”安装该命令行工具;
|
||||
</li>
|
||||
<li>
|
||||
访问https://www.webpagetest.org/getkey.php获取你的WebPagetest API Key;
|
||||
</li>
|
||||
<li>
|
||||
使用“webpagetest test -k API-KEY 被测页面URL”发起测试,该调用是异步操作,会立即返回,并为你提供一个testId;
|
||||
</li>
|
||||
<li>
|
||||
使用“webpagetest status testId”查询测试是否完成;
|
||||
</li>
|
||||
<li>
|
||||
测试完成后,就可以通过“webpagetest results testId”查看测试报告,但是你会发现测试报告是个很大的JSON文件,可读性较差;
|
||||
</li>
|
||||
<li>
|
||||
通过“npm install webpagetest-mapper -g”安装webpagetest-mapper工具,这是为了解决测试报告可读性差的问题,将WebPagetest生成的JSON文件格式的测试报告转换成为HTML文件格式;
|
||||
</li>
|
||||
<li>
|
||||
使用“Wptmap -key API-KEY --resultIds testId --output ./test.html”将JSON文件格式的测试结果转换成HTML格式。
|
||||
</li>
|
||||
|
||||
## 总结
|
||||
|
||||
今天,我使用WebPagetest测试了一个具体网站的前端性能。在解读这个测试报告的同时,我和你分享了几个重要的前端性能指标,以及如何提升这些指标,最终达到优化网站用户体验的目的。
|
||||
|
||||
虽然,WebPagetest是一款免费的、功能强大的前端性能测试工具,但是用于实际测试项目时,往往还存在两个方面的问题,我给你分析了这两个问题出现的原因,以及如何解决这两个问题,以达到更高效地完成前端性能测试的目的。
|
||||
|
||||
## 思考题
|
||||
|
||||
除了我今天介绍的WebPagetest外,前端测试工具还有YSlow等。你还在工作中接触过哪些前端性能测试工具,它们各自有什么特点呢?
|
||||
|
||||
感谢收听,欢迎你给我留言。
|
||||
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
<audio id="audio" title="32 | 无实例无真相:基于LoadRunner实现企业级服务器端性能测试的实践(上)" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/de/54/de2e0aafb90de53dc3afeb5be5b23254.mp3"></audio>
|
||||
|
||||
你好,我是茹炳晟。今天我和你分享的主题是:无实例无真相之基于LoadRunner实现企业级服务器端性能测试的实践(上)。
|
||||
|
||||
从今天开始的两篇文章,我将介绍如何基于LoadRunner实际开展企业级服务器端的性能测试。分享这个主题时,我会从最开始的性能需求获取开始讲起,带你完整地经历一个实际服务器端性能测试项目。通过这个过程,我希望可以帮助你快速建立服务器端性能测试的全局观,并了解各主要步骤的关键技术细节。
|
||||
|
||||
听到这里,你可能就有些困惑了。我在分享[《工欲善其事必先利其器:后端性能测试工具原理与行业常用工具简介》](https://time.geekbang.org/column/article/16589)这个主题时,曾经说到:LoadRunner比较适合于传统软件企业开展性能测试,而JMeter更适用于互联网企业的软件性能测试。那么,为什么我没有选择以JMeter为例来展开后端性能测试呢?
|
||||
|
||||
我选择LoadRunner,是经过深思熟虑的,主要原因包括:
|
||||
|
||||
<li>
|
||||
**JMeter的官方文档对其使用方法介绍得很详细,而且其操作基本属于“傻瓜式”的**。JMeter使用的难点在于:如何支持海量并发,以及实现更好的load控制,解决这个问题你可以参考LoadRunner的实现方式,然后从你所在企业的实际业务场景出发,进行二次开发。
|
||||
</li>
|
||||
<li>
|
||||
**互联网企业和传统软件企业的软件产品的后端性能测试,在原理以及基本方法上是基本一致的,区别较大的只是全链路压测**。所以,我以传统企业的软件产品为例展开分享,你因此学到的原理以及测试方法将同样适用于互联网软件产品的性能测试。
|
||||
</li>
|
||||
<li>
|
||||
**关于互联网软件产品的全链路压测,由于需要实现海量并发以及流量隔离等操作,所以目前只有一些大型企业在做,比如饿了么、淘宝、ebay、美团等超级大的网站**。但是,如果你也想了解全链路压测的话,我也会准备一篇“加餐”文章,和你分享开展全链路压测的难点,以及应对方案。我会更新完性能测试这个系列以后,为你准备这篇“加餐”文章。
|
||||
</li>
|
||||
|
||||
为了让你在进行服务器端性能测试时更充分地利用好LoadRunner,所以在正式开始讲解这个测试案例前,我会先给你简单介绍一下LoadRunner的基本原理,以及主要的功能模块。这些功能模块不仅在这个案例中会用到,也会在实际工程项目被经常使用,所以如果你有什么不理解的地方,欢迎给我留言。
|
||||
|
||||
## LoadRunner的基本原理
|
||||
|
||||
你还记得我在[《工欲善其事必先利其器:后端性能测试工具原理与行业常用工具简介》](https://time.geekbang.org/column/article/16589)这个主题中,介绍过的后端性能测试工具的基本原理吗?
|
||||
|
||||
我们先一起来回忆一下吧:
|
||||
|
||||
>
|
||||
后端性能测试工具首先通过**虚拟用户脚本生成器**生成基于协议的虚拟用户脚本,然后根据性能测试场景设计的要求,通过**压力控制器**控制协调各个**压力产生器**以并发的方式执行虚拟用户脚本,并且在测试执行过程中,通过**系统监控器**收集各种性能指标以及系统资源占用率,最后通过**测试结果分析器**展示测试结果数据。
|
||||
|
||||
|
||||
LoadRunner的基本原理,与上面的描述完全一致。在LoadRunner中,Virtual UserGenerator对应的就是虚拟用户脚本生成器,Controller
|
||||
|
||||
对应的就是压力控制器和系统监控器,Load Generator对应的就是压力产生器,Analysis对应的就是测试结果分析器。
|
||||
|
||||
为了帮助你理解LoadRunner的工作原理和模块,先撇开这些名词不谈,设想一下如果没有专用的后端性能测试工具,我们如何开展后端性能测试。
|
||||
|
||||
其实,“人肉”开展后端性能测试也不算太难。这个过程大致是这样的:
|
||||
|
||||
- 首先,我们需要一批测试机器,每台测试机器雇佣一个测试人员;
|
||||
- 然后,我们需要一个协调员拿着话筒发号施令,统一控制这些测试人员的步调,协调员会向所有测试人员喊话,比如“1号到100号测试人员现在开始执行登录操作,100号到1000号测试人员5分钟后开始执行搜索操作”,同时协调员还会要求每个测试人员记录操作花费的时间;
|
||||
- 测试完成后,测试协调员会要求性能工程师分析测试过程中记录的数据。
|
||||
|
||||
这个过程,如图1所示。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/d9/43/d96d730ea9b63a9371149465af9d3143.png" alt="">
|
||||
|
||||
理解了这种“人肉”模式的后端性能测试后,我们再回过头来看LoadRunner的各个模块就豁然开朗了。
|
||||
|
||||
- 测试协调员以及完成数据记录的部分就是Controller模块;
|
||||
- 大量的测试机器以及操作这些测试机器的人就是Load Generator模块;
|
||||
- 操作这些测试机器的人的行为就是Virtual User Generator产生的虚拟用户脚本;
|
||||
- 对测试数据的分析就是Analysis模块。
|
||||
|
||||
## LoadRunner的主要模块
|
||||
|
||||
通过对“人肉”模式和LoadRunner工具的类比,我们可以很清楚的看到,使用LoadRunner进行性能测试,主要需要Virtual User Generator、Controller(这个模块包含了Load Generator),以及Analysis这三大模块组合使用。接下来,我再和你详细聊聊这三大模块的作用,以及需要注意的问题。
|
||||
|
||||
**第一,Virtual User Generator**
|
||||
|
||||
Virtual User Generator,用于生成模拟用户行为的测试脚本,生成的手段主要是基于协议的录制,也就是由性能测试脚本开发人员在通过GUI执行业务操作的同时,录制客户端和服务器之间的通信协议,并最终转化为代码化的LoadRunner的虚拟用户脚本。
|
||||
|
||||
这样转化得到的虚拟脚本往往并不能被直接使用,还需要经历数据参数化(Parameterization)、关联建立(Correlation),以及运行时设置(Run Time Settings)等操作,然后才能用于性能测试场景中。
|
||||
|
||||
具体什么是数据参数化、什么是关联建立、运行时设置都有哪些可选项,我会在分享实例时再详细展开。
|
||||
|
||||
**第二,LoadRunner Controller**
|
||||
|
||||
Controller相当于性能测试执行的控制管理中心,负责控制Load Generator产生测试负载,以执行预先设定好的性能测试场景;同时,它还负责收集各类监控数据。
|
||||
|
||||
在实际执行性能测试时,Controller是和性能工程师打交道最多的模块,性能工程师会在Controller的UI界面上完成性能测试场景的设计、运行时的实时监控、测试负载的开始与结束等操作。
|
||||
|
||||
**第三,LoadRunner Analysis**
|
||||
|
||||
Analysis是LoadRunner中一个强大的分析插件。它不仅能图形化展示测试过程中收集的数据,还能很方便地对多个指标做关联分析,找出它们之间的因果关系。它最根本的目的就是,分析出系统可能的性能瓶颈点以及潜在的性能问题。
|
||||
|
||||
现在,你已经了解了LoadRunner的原理和各个模块了,接下来我们就开始实战吧。通过这个实战,我希望你可以掌握如何基于LoadRunner进行企业级的性能测试。
|
||||
|
||||
从宏观角度来讲,基于LoadRunner完成企业级性能测试,可以划分为五个阶段:
|
||||
|
||||
<li>
|
||||
性能需求收集以及负载计划制定;
|
||||
</li>
|
||||
<li>
|
||||
录制并增强虚拟用户脚本;
|
||||
</li>
|
||||
<li>
|
||||
创建并定义性能测试场景;
|
||||
</li>
|
||||
<li>
|
||||
执行性能测试场景;
|
||||
</li>
|
||||
<li>
|
||||
分析测试报告。
|
||||
</li>
|
||||
|
||||
图2清晰地描述了这5个阶段的先后顺序,以及需要LoadRunner各模块发挥作用的部分。接下来,我和你详细聊聊每个阶段的具体工作,以及关键的技术细节。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e8/94/e8e58ca14e80346be38291cf84bf2394.png" alt="">
|
||||
|
||||
## 阶段1:性能需求收集以及负载计划制定
|
||||
|
||||
其实,无论是进行什么类型的测试,你的第一步工作都是要根据测试目的明确测试的具体需求。企业级的后端性能测试,当然也不例外。
|
||||
|
||||
一般情况下,企业级后端性能测试的具体需求,主要包含以下内容:
|
||||
|
||||
- **系统整体的并发用户数**。比如,高峰时段会有10万用户同时在线;
|
||||
- **并发用户业务操作的分布情况**。比如,20%的用户在做登录操作,30%的用户在做订单操作,其他50%的用户在做搜索操作;
|
||||
- **单一业务操作的用户行为模式**。比如,两个操作之间的典型停留时间,完成同一业务的不同操作路径等;
|
||||
- **并发用户高峰期的时间分布规律**。比如,早上8点会有大量用户登录系统,晚上6点后用户逐渐退出;
|
||||
- **达到最高峰负载的时间长度**。比如,并发用户从0增长到10万花费的总时间;
|
||||
- …
|
||||
|
||||
完成这些点的测试,其实并不复杂。你只要按照这个已经明确的需求,开发后续的测试脚本、设计性能测试场景就可以了。
|
||||
|
||||
但是,如果你想要成长为更资深的性能测试工程师,或者已经是性能测试的设计者、资深的性能测试工程师了,那么你就需要全程参与到这些需求的获取和确定中。
|
||||
|
||||
其实,在我看来,获取这些测试需求时性能测试中最难的两个工作之一。另一个最难的工作是,测试结果分析与性能问题定位。而其他类似性能测试脚本开发、场景设计等工作看起来很有技术含量,但实际都是一些相对机械性的重复工作。
|
||||
|
||||
那为什么获取测试需求难做呢?因为绝大多数情况下没人会明确告诉你具体的性能需求。
|
||||
|
||||
对于软件的功能测试来说,如果需求不明确,你可以直接求助于产品经理。
|
||||
|
||||
而对性能测试需求来讲,产品经理通常无法准确告诉你用户的各个业务操作所占的百分比,也无法告诉你准确的用户行为模式。产品经理能做的,往往是给出定性描述,然后需要你去计算或者根据过往经验得到具体的定量需求。所以,我们经常会听到产品经理对性能测试人员说:“你是性能专家,你来告诉我性能需求”。
|
||||
|
||||
那么,对于性能测试设计人员来说,到底如何获得这个明确的性能需求呢?说到这里,你应该明白了这是一个非常复杂的话题,因为测试目的不同,所用的方法也各不相同。所以,在这次分享中,我也只是可以给你准备一个实际的测试案例,和你分享获取具体测试需求的思考方式。
|
||||
|
||||
还记得我在第29篇文章[《聊聊性能测试的基本方法与应用领域》](https://time.geekbang.org/column/article/14832)中介绍的医院体检的例子吗?假设,产品经理对医院体检的性能要求是“每天支持完成8000个体检”,这个需求看似很具体,但是要转化成实际可操作的性能测试需求,还需要再细化。
|
||||
|
||||
**首先,你要明确这里的“每天”是否指的是24小时**。显然,这取决于产品本身的属性。比如,产品是为单一时区的用户提供服务,还是要面向全球所有时区的用户。那么,根据体检中心的属性,你很容易就可以确定“每天”一定是指8小时的工作时间。因为,体检中心一定是在一个确定的时区,并且不会24小时营业。
|
||||
|
||||
**然后,你明确了这个8小时后,那么原始需求是不是可以转化为“每小时支持完成1000个体检”?**
|
||||
|
||||
如果按照这个套路设计后续的性能测试的话,你会发现即使测试顺利完成,并且各项性能指标都达标了,但是一旦上线后,系统还是很有可能被压垮。因为实际情况是,验血往往需要空腹,所以上午往往是体检中心的高峰时段,体检者会在上午集中涌入体检中心。也就是说,这8000个体检并不是平均分布在8小时内完成的,而是有明显的高峰时段。
|
||||
|
||||
**最后,你可以采用80/20原则对高峰时段的用户负载进行建模**,比如80%的体检(6400个)是发生在上午20%的时间(96分钟)里。当然,为了使模型更接近真实的情况,你还应该分析历史数据,然后对该模型做进一步的修正,这也是目前被普遍采用的方法。
|
||||
|
||||
另外,在得到了负载模型后,性能测试设计人员往往还会在此基础上加入一定的负载冗余,比如在峰值的基础上再额外放大20%,以增强系统上线后稳定运行的信心。
|
||||
|
||||
通过上面这个分析过程,你可以认识到,性能测试需求的定义与计划非常复杂,牵涉到项目的方方面面,不可能通过阅读一两篇文章就快速掌握这一技能,需要不断地沉淀在实战中获得的经验。
|
||||
|
||||
制订了性能测试计划后,接下来你就需要根据性能计划中涉及的用户业务操作来开发性能测试的脚本了。比如,前面提到“20%的用户在做登录操作,30%的用户在做订单操作,剩下50%的用户在做搜索操作”,接下来你需要分别开发“用户登录”“下订单”和“搜索”这三个虚拟用户脚本。
|
||||
|
||||
在LoadRunner中,开发虚拟用户脚本的工作主要是基于录制后再修改的方式完成的。其中,录制由Virtual UserGenerator基于协议完成,录制后的修改主要是实现参数化、建立关联、建立事务、加入必要的检查点以及加入思考时间。
|
||||
|
||||
所以,我会在下次分享时,和你详细讨论这四部分工作的作用,以及具体如何完成。同时,我还会和你分享,企业级服务器端性能测试的后四个阶段如何实现。
|
||||
|
||||
## 总结
|
||||
|
||||
今天我和你讨论的主题是,如何基于LoadRunner实现企业级服务器端性能测试。
|
||||
|
||||
首先,我用一个“人肉”测试的流程类比,为你介绍了LoadRunner这个工具的基本原理,并分析了Virtual User Generator、Controller(内含Load Generator模块),以及Analysis这3个模块的功能。
|
||||
|
||||
然后,从宏观角度,我把整个性能测试过程划分成了五个阶段:性能需求收集以及负载计划制定、录制并增强虚拟用户脚本、创建并定义性能测试场景、执行性能测试场景,以及分析测试报告。
|
||||
|
||||
在我看来,这五个阶段最难的两部分工作分别是:明确具体的性能测试需求,以及测试结果分析与性能问题定位。因为这两部分工作,要大量依赖于测试工程师的能力以及经验积累。所以,就像一名优秀的医生一样,优秀的测试工程师,需要在实际的工程项目中不断积累和总结经验。
|
||||
|
||||
最后,我以前面文章提到过的体检中心为例,和你详细讨论了如何收集性能需求,以及制定负载计划的内容。我也解释了为什么性能测试的需求不能直接从产品经理那里获得:因为产品经理定义的性能需求层次比较高、比较抽象,要落实到实际可执行的性能测试需求往往需要分析和细化。这也是为什么获取具体的性能需求比较难的一个原因。
|
||||
|
||||
## 思考题
|
||||
|
||||
你在实际工作中,是如何获取并细化性能测试需求的呢?
|
||||
|
||||
感谢你的收听,欢迎你给我留言。
|
||||
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
<audio id="audio" title="33 | 无实例无真相:基于LoadRunner实现企业级服务器端性能测试的实践(下)" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/54/5a/54f12c2bb150c91e5d36eed755ab105a.mp3"></audio>
|
||||
|
||||
你好,我是茹炳晟。今天我和你分享的主题是:无实例无真相之基于LoadRunner实现企业级服务器端性能测试的实践(下)。
|
||||
|
||||
今天,我会继续和你分享如何基于LoadRunner完成企业级服务器端的性能测试。通过我上一次的分享,你已经清楚知道了,整个性能测试过程可以分为五个阶段,并且解决了整个测试过程中最难的一部分工作,即如何获取具体的性能测试需求。
|
||||
|
||||
现在,我们先来回顾一下,性能测试包含的五个阶段:性能需求收集以及负载计划制定、录制并增强虚拟用户脚本、创建并定义性能测试场景、执行性能测试场景,以及分析测试报告。所以,今天,我们就要解决剩下的4个阶段的问题了。
|
||||
|
||||
## 阶段2:录制并增强虚拟用户脚本
|
||||
|
||||
我已经在上篇文章中和你提到,完成了性能测试需求分析后,你就已经明确了要开发哪些性能测试脚本。现在,我们就一起来看看开发性能测试脚本的步骤,以及相关的技术细节。
|
||||
|
||||
从整体角度来看,用LoadRunner开发虚拟用户脚本主要包括以下四个步骤:
|
||||
|
||||
<li>
|
||||
识别被测应用使用的协议;
|
||||
</li>
|
||||
<li>
|
||||
录制脚本;
|
||||
</li>
|
||||
<li>
|
||||
完善录制得到的脚本;
|
||||
</li>
|
||||
<li>
|
||||
验证脚本的正确性。
|
||||
</li>
|
||||
|
||||
这里需要注意的是,完善录制得到的脚本这一步,会包含大量的技术细节,也有很多对你来说可能是新概念的名词,所以我会着重讲解这一步,帮你克服性能测试道路上的这些“拦路虎”。
|
||||
|
||||
**步骤1:识别被测应用使用的协议**
|
||||
|
||||
如果你已经和系统设计、开发人员沟通过,明确知道了被测系统所采用的协议,那么你可以跳过这一步。如果还不知道具体使用的哪种协议的话,你可以使用Virtual User Generator模块自带的Protocol Advisor识别被测应用使用的协议,具体的操作方法也很简单:
|
||||
|
||||
<li>
|
||||
在Virtual User Generator中依次点击File、Protocol、AdvisorAnalyze、Application,展开这些菜单。
|
||||
</li>
|
||||
<li>
|
||||
在打开的界面上按要求填写被测应用的信息。
|
||||
</li>
|
||||
<li>
|
||||
Protocol Advisor会自动运行被测系统。如果是网页应用,就会打开浏览器。
|
||||
</li>
|
||||
<li>
|
||||
在页面上执行一些典型的业务操作,完成这些业务操作后点击"Stop Analyzing"按钮停止录制。
|
||||
</li>
|
||||
<li>
|
||||
Protocol Advisor会根据刚才录制的内容自动分析被测应用使用的协议,并给出最终的建议。
|
||||
</li>
|
||||
|
||||
接下来,你就可以使用Protocol Advisor建议的录制协议开始脚本录制工作了。如图1所示就是Protocol Advisor给出的建议录制协议界面。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/9a/20/9a8c760f3de2eaa1c5be274c70215920.png" alt="" />
|
||||
|
||||
**步骤2:录制脚本**
|
||||
|
||||
脚本录制的基本原理是,通过GUI界面对被测系统进行业务操作,Virtual User Generator模块在后台捕获GUI操作所触发的客户端与服务器端的所有交互,并生产基于C语言的虚拟用户脚本文件。
|
||||
|
||||
也就是说,录制脚本的过程需要通过GUI实际执行业务操作,所以我建议你在开始录制脚本前,先多次演练需要这些GUI操作步骤,并明确知道哪些操作步骤会对服务器端发起请求。
|
||||
|
||||
我们要知道哪些操作步骤会对服务器发起请求的原因是,要将这些操作步骤在虚拟用户脚本中封装成“事务”(Transaction)。封装为“事务”的目的是统计响应时间,因为LoadRunner中的响应时间都是以“事务”为单位的。
|
||||
|
||||
具体的录制步骤,主要包括如下三步,
|
||||
|
||||
<li>
|
||||
首先,选择Create/Edit Scripts进入Virtual User Generator创建脚本的协议选择界面。
|
||||
</li>
|
||||
<li>
|
||||
选择正确的协议后进入Start Recording界面,选择需要录制的应用类型,并填写应用的详细信息。如果是Web应用,Application type就应该选择Internet Application,然后选择浏览器并填写这个Web应用的URL,完成后自动打开浏览器。
|
||||
</li>
|
||||
<li>
|
||||
在该浏览器中执行业务操作,Virtual User Generator模块会记录所有的业务操作,并生成脚本。
|
||||
</li>
|
||||
|
||||
**在录制脚本的过程中,我强烈建议直接对发起后端调用的操作添加事务定义,而不要等到脚本生成后再添加**。因为LoadRunner脚本的可读性并不好,在录制完的脚本中添加事务定义的难度会很大。
|
||||
|
||||
在录制过程中,直接添加事务操作也很简单,主要包括如下三步:
|
||||
|
||||
<li>
|
||||
在开始执行GUI操作前,先点击图2中的“事务开始”按钮并填写事务名称;
|
||||
</li>
|
||||
<li>
|
||||
执行GUI操作;
|
||||
</li>
|
||||
<li>
|
||||
操作完成后,点击图2中的“事务结束”按钮。
|
||||
</li>
|
||||
|
||||
这样你刚才执行GUI操作的脚本就会被lr_start_transaction(“事务名称”)和lr_end_transaction(“事务名称”,LR_AUTO)包围起来,也就完成了添加事务的定义。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/66/34/6636bbd8056a7e992239fbb3b81bf134.png" alt="" />
|
||||
|
||||
**步骤3:完善录制得到的脚本**
|
||||
|
||||
脚本录制,只是虚拟用户脚本开发中最简单的一步。我在上一次分享《无实例无真相:基于LoadRunner实现企业级服务器端性能测试的实践(上)》时,提到由Virtual User Generator模块录制的脚本不能直接使用,我们还需要对录制的脚本做以下处理:
|
||||
|
||||
- 在两个事务之间加入思考时间(Think Time);
|
||||
- 对界面输入的数据做参数化(Parameterization)操作;
|
||||
- 完成脚本的关联(Correlation)操作;
|
||||
- 加入检查点(Check Point)。
|
||||
|
||||
这4步处理操作是虚拟用户脚本开发中最关键的地方,你不仅需要知道为什么要进行这些处理,更要能够完成这些处理,否则你录制的脚本无法成功回放。
|
||||
|
||||
**第一,在两个事务之间加入思考时间**
|
||||
|
||||
什么是思考时间呢?
|
||||
|
||||
用户在实际使用系统时,并不会连续不断地向后端服务器发起请求,在两次发起请求之间往往会有一个时间的间隔,这个时间间隔主要来自于两个方面:
|
||||
|
||||
- 一是,用户操作的人为等待时间,因为用户不可能像机器人那样快速地执行操作;
|
||||
- 二是,用户可能需要先在页面上填写很多信息后之后,才能提交操作,那么填写这些信息就需要花费一定的时间。
|
||||
|
||||
所以,为了让虚拟用户脚本能够更真实地模拟实际用户的行为,我们就需要在两个事务之间加入一定的等待时间。这个等待时间,就是LoadRunner中的思考时间。
|
||||
|
||||
你只要直接调用LoadRunner提供的lr_think_time()函数,就可以在两个事务之间加入思考时间。但是,这个思考时间到底设置为多少,并没有那么容易知道。思考时间往往会涉及多方面的因素,严格计算的话会非常复杂。
|
||||
|
||||
所以,**在实际项目中,一般先粗略估计一个值(比如15 s),然后在实际执行负载场景的过程中,再根据系统吞吐量调整。**
|
||||
|
||||
你在后续调整思考时间时,无需逐行修改虚拟用户脚本代码,可以在Run-time Settings(运行时设置)中很方便地完成。如图3所示,Run-time Settings中支持多种方式调整思考时间。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/9b/9b/9bc228a755cb104b34bcc55e6e460c9b.png" alt="" />
|
||||
|
||||
- As recorded,代表的是直接使用lr_think_time()函数中指定的时间。
|
||||
- Mutiply recorded think time by,代表的是在lr_think_time()函数中指定的时间基础上乘以一个数字。比如这个数字是2,那么所有的思考时间都会翻倍。
|
||||
- Use random percentage of recorded think time,指的是使用指定思考时间范围内的随机值。例如,如果lr_think_time()函数中指定的时间是2 s,并且指定最小值为50%,最大值为200%,则实际的思考时间会取最小值1 s(2 s**50%)和最大值4 s(2 s**200%)之间的随机值。
|
||||
- Limit think time to,指的是为思考时间设置一个上限值,只要lr_think_time()函数中指定的时间没有超过这个上限值,就按照lr_think_time()函数指定的值,如果超过了就取这个上限值作为思考时间。
|
||||
|
||||
**第二,对界面输入的数据做参数化操作**
|
||||
|
||||
数据的参数化,其实很好理解,我再给你举个例子,你马上就能明白。
|
||||
|
||||
假设,你录制的虚拟用户脚本完成的是用户登录操作,那么由于脚本回放时需要支持多用户的并发,所以必须要把脚本中的用户名和密码独立出来,放入专门的数据文件中,然后在这个文件中提供所有可能被用到的用户名和密码。
|
||||
|
||||
有没有感觉这个概念很熟悉,它其实和我以前介绍到的[数据驱动的自动化测试](https://time.geekbang.org/column/article/11966)完全相同。
|
||||
|
||||
图4给出了参数化配置的界面截图,LoadRunner支持的参数化的数据源很丰富,既可以是excel文件,也可以是数据库中的表等。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/41/77/414fcea000ef8a968cd25d5fbc5ee477.png" alt="" />
|
||||
|
||||
这里需要特别说明的是,凡是参数文件中使用的测试数据都需要在执行性能测试前,在被测系统中事先准备好。比如,还是以用户登录的脚本为例,假定你的参数文件中提供了5000个用于并发执行的用户信息,那么这5000个用户必须是已经实际存在于系统中的,这就要求你要在开始测试前事先准备好这5000个用户。
|
||||
|
||||
所以,参数化操作其实由两部分组成:
|
||||
|
||||
<li>
|
||||
性能测试脚本和测试数据的分离;
|
||||
</li>
|
||||
<li>
|
||||
事先建立性能测试的数据。
|
||||
</li>
|
||||
|
||||
也就是说,参数化的过程往往与性能测试数据准备密不可分。
|
||||
|
||||
**第三,完成脚本的关联操作**
|
||||
|
||||
关联操作,是LoadRunner虚拟用户脚本开发过程中最关键的部分,直接关系到脚本是否可以回放成功。
|
||||
|
||||
从概念上讲,关联的主要作用是,取出前序调用返回结果中的某些动态值,传递给后续的调用。是不是听起来很拗口,不太好理解?我们来看一个具体的例子吧。
|
||||
|
||||
假设,每次客户端连接服务器端时,服务器端都会用当前的时间戳(Time Stamp)计算CheckSum,然后将Time Stamp和CheckSum返回给客户端。然后,客户端就把Time Stamp + CheckSum的组合作为唯一标识客户端的Session ID。录制脚本时,录制得到的一定是硬编码(hardcode)的Time Stamp值和CheckSum值。
|
||||
|
||||
图5展示了这个交互过程,录制得到Time Stamp的值是TS,而CheckSum的值是CS。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/f2/02/f275c421d12a323f9ddcff63a4873c02.png" alt="" />
|
||||
|
||||
采用Time Stamp + CheckSum的组合作为Session ID的方式,在我们回放这个脚本的时候就有问题了。因为回放时,这段硬编码已经有了新的Time Stamp值和CheckSum值,并且显然与之前的值不同,所以服务器无法完成Session ID的验证,也就导致了脚本回放失败。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/d8/df/d8cdec2de5664b2d5b4288514c9cd4df.png" alt="" />
|
||||
|
||||
其实,这种情况几乎存在于所有的虚拟用户脚本中,所以我们必须要解决这个问题。
|
||||
|
||||
解决方法就是,在脚本回放的过程中,实时抓取Time Stamp值和CheckSum值,然后用实时抓取到的值替换后续需要使用这两个值的地方。这个过程就是“关联”。
|
||||
|
||||
如图7所示,**关联就是解析服务器端的返回结果,抓取新的Time Stamp值和CheckSum值,然后后续的操作都使用新抓取的值,这样脚本就能回放成功了。**
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/33/8f/33675b6e6a3b008cb3ebb16af58e6a8f.png" alt="" />
|
||||
|
||||
理解了关联操作,在脚本中处理关联就比较简单了,LoadRunner提供了功能强大的关联函数web_reg_save_param()。这个关联函数支持多种动态值的获取方式,用得最多的是基于“前序字符串匹配”加上“后续字符串匹配”的方式。其中,字符串匹配,支持正则表达式。
|
||||
|
||||
我们一起来看个具体的例子吧。
|
||||
|
||||
假设,服务器端返回的结果是“LB=name=timestamp value=8888.LB=name=CheckSum”,那么为了能够获取到“8888”这个动态值,我们就可以用“前序字符串=LB=name=timestamp value=”和“后续字符=.LB=name=CheckSum”来“框出” 8888”这个动态值。
|
||||
|
||||
另外,需要特别注意的是web_reg_save_param()函数是注册型函数,必须放在获取动态值所属的请求前面,相当于先声明,后调用。
|
||||
|
||||
更多的关联函数用法,你可以参考LoadRunner官方文档。
|
||||
|
||||
**第四,加入检查点**
|
||||
|
||||
检查点,类似于功能测试中的断言。但是,性能测试脚本,不像功能测试脚本那样需要加入很多的断言,往往只在一些关键步骤后加入很少量的检查点即可。这些检查点的主要作用是,保证脚本按照原本设计的路径执行。
|
||||
|
||||
最常用的检查点函数是web_reg_find(),它的作用是通过指定左右边界的方式“在页面中查找相应的内容”。这里需要注意的是,这个函数也是注册型函数,即需要放在所检查的页面之前,否则会检查失败。更多的检查点函数以及用法也请参考LoadRunner官方文档。
|
||||
|
||||
**步骤4:验证脚本的正确性**
|
||||
|
||||
完成了脚本开发后,根据我的个人经验,我强烈建议你按照以下顺序检查脚本的准确性:
|
||||
|
||||
<li>
|
||||
以单用户的方式,在有思考时间的情况下执行脚本,确保脚本能够顺利执行,并且验证脚本行为以及执行结果是否正确;
|
||||
</li>
|
||||
<li>
|
||||
以单用户的方式,在思考时间为零的情况下执行脚本,确保脚本能够顺利执行,并且验证脚本行为以及执行结果是否正确;
|
||||
</li>
|
||||
<li>
|
||||
以并发用户的方式,在有思考时间的情况下执行脚本,确保脚本能够顺利执行,并且验证脚本行为以及执行结果是否正确;
|
||||
</li>
|
||||
<li>
|
||||
以并发用户的方式,在思考时间为零的情况下执行脚本,确保脚本能够顺利执行,并且验证脚本行为以及执行结果是否正确。
|
||||
</li>
|
||||
|
||||
只有上述四个测试全部通过,虚拟用户脚本才算顺利完成。
|
||||
|
||||
至此,我们完成了第二个阶段的“录制并增强虚拟用户脚本”的工作,顺利拿到了虚拟用户脚本。那么接下来,我们就会进入第三个阶段,使用开发完成的虚拟用户脚本创建并定义性能测试场景。
|
||||
|
||||
## 阶段3:创建并定义性能测试场景
|
||||
|
||||
还记得我在分享《[工欲善其事必先利其器:后端性能测试工具原理与行业常用工具简介](https://time.geekbang.org/column/103)》这个主题时,介绍过的性能测试场景的内容吗?如果有点忘记了,我建议你先回顾一下这篇文章的内容。
|
||||
|
||||
这个阶段的工作,就是在LoadRunner Controller中设置性能测试场景。由于整个设置过程,都是基于Controller的图形用户界面的操作,本身没什么难度,所以我就不再详细展开了,如果有这方面的问题,你也可以自行百度或者给我留言。
|
||||
|
||||
## 阶段4:执行性能测试场景
|
||||
|
||||
完成了性能测试场景的设计与定义后,执行性能测试场景就非常简单了。
|
||||
|
||||
这个过程一般是在LoadRunner Controller中完成。你可以通过Controller发起测试、停止测试、调整性能测试场景的各种参数,还可以监控测试的执行过程。
|
||||
|
||||
## 阶段5:分析测试报告
|
||||
|
||||
执行完性能测试后,LoadRunner会根据自己的标准并结合性能测试场景中定义的系统监控器指标,生成完整的测试报告。在Analysis中,不仅可以以图形化的方式显示单个指标,也可以将多个指标关联在一起进行比较分析。
|
||||
|
||||
图8展示了使用LoadRunner Analysis展示事务平均响应时间的界面,我们可以看到图片右下角各个事务的最小响应时间、最大响应时间和平均响应时间。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/88/ea/88f90cc95b59e24a5c7b19848433fcea.png" alt="" />
|
||||
|
||||
性能测试报告的分析,是一项技术含量非常高的工作。优秀的性能测试工程,通过报告中的数值以及数值之间的相互关系,就能判断出系统中可能存在的问题。这就好比医生看验血报告,经验丰富的医生可以根据验血报告对病情做出八九不离十的判断。
|
||||
|
||||
性能测试报告的解读,需要丰富的系统架构、性能理论以及大量实战经验的积累。这个话题已经超出了我今天要分享的范围,所以我也就不再继续展开了。
|
||||
|
||||
## 总结
|
||||
|
||||
今天接着上一篇文章,我和你分享了企业级后端性能测试的后四个阶段的内容,包括录制并增强虚拟用户脚本、创建并定义性能测试场景、执行性能测试场景,以及分析测试报告。现在,我再为你总结一下每一个阶段的重点内容。
|
||||
|
||||
录制并增强虚拟用户脚本,这个阶段的工作又可以分为识别被测应用使用的协议、录制脚本、完善录制得到的脚本、验证脚本的正确性四步。其中,完善录制得到的脚本这一步,涉及到了很多概念和基础知识,所以我进行了重点讲解,希望帮你克服性能测试的难点。
|
||||
|
||||
创建并定义性能测试场景,以及执行性能测试场景,这两个阶段的工作都是在LoadRunner的Controller模块中完成的,也都比较简单。你可以参考我在《工欲善其事必先利其器:后端性能测试工具原理与行业常用工具简介》这篇文章分享的内容,完成这两个阶段的工作。
|
||||
|
||||
分析测试报告,这个工作的技术含量非常高。深入解读性能测试报告的能力,需要丰富的系统架构、性能理论,以及大量实战经验。所以,我们需要在平时工作中,不断地丰富自己的知识体系。
|
||||
|
||||
## 思考题
|
||||
|
||||
你们公司的性能测试是否使用LoadRunner,在使用过程中遇到了什么难题?你们又是如何解决的呢?
|
||||
|
||||
感谢你的收听,欢迎你给我留言。
|
||||
|
||||
|
||||
146
极客时间专栏/软件测试52讲/性能测试篇/34 | 站在巨人的肩膀:企业级实际性能测试案例与经验分享.md
Normal file
146
极客时间专栏/软件测试52讲/性能测试篇/34 | 站在巨人的肩膀:企业级实际性能测试案例与经验分享.md
Normal file
@@ -0,0 +1,146 @@
|
||||
<audio id="audio" title="34 | 站在巨人的肩膀:企业级实际性能测试案例与经验分享" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/f8/2f/f8b5876324d7669753aa973e7f92042f.mp3"></audio>
|
||||
|
||||
你好,我是茹炳晟,今天我分享的主题是:站在巨人的肩膀之企业级实际性能测试案例与经验分享”。
|
||||
|
||||
在前面的四篇文章中,我介绍了前端性能测试和后端性能测试的理论与方法,还分享了使用LoadRunner实现后端性能测试的过程。有了这些内容的铺垫,我今天会和你聊聊传统的企业级软件企业如何开展性能测试工作。
|
||||
|
||||
其实,传统的企业级软件产品和互联网产品的性能测试,在原理和测试方法上基本一致,它们最大的区别体现在并发数量的数量级上,以及互联网软件产品的性能测试还需要直接在生产环境下进行特有的全链路压测。而全链路压测其实是在传统的企业级软件产品的性能测试基础上,又进行了一些扩展。
|
||||
|
||||
所以,在我看来,只要掌握了传统的企业级软件产品的性能测试的原理和方法,搞定互联网产品的性能测试自然不在话下。
|
||||
|
||||
言归正传,传统企业级软件产品的性能测试重点是在服务器端。为了达到不同的测试目标,往往会有多种不同类型的性能测试。今天,我就和你聊聊这其中都有哪些测试类型,以及每类测试的目的、所采用的方法。
|
||||
|
||||
所以,今天的分享,我会从以下四种测试类型的角度展开:
|
||||
|
||||
<li>
|
||||
性能基准测试;
|
||||
</li>
|
||||
<li>
|
||||
稳定性测试;
|
||||
</li>
|
||||
<li>
|
||||
并发测试;
|
||||
</li>
|
||||
<li>
|
||||
容量规划测试。
|
||||
</li>
|
||||
|
||||
## 性能基准测试
|
||||
|
||||
性能基准测试,通常被称为Performance Benchmark Test,是每次对外发布产品版本前必须要完成的测试类型。
|
||||
|
||||
性能基准测试,会基于固定的硬件环境和部署架构(比如专用的服务器、固定的专用网络环境、固定大小的集群规模、相同的系统配置、相同的数据库背景数据等),通过执行固定的性能测试场景得到系统的性能测试报告,然后与上一版本发布时的指标进行对比,如果发现指标有“恶化”的趋势,就需要进一步排查。
|
||||
|
||||
典型的“恶化”趋势,主要表现在以下几个方面:
|
||||
|
||||
- **同一事务的响应时间变慢了**。比如,上一版本中,用户登录的响应时间是2 s,但是在最新的被测版本中这个响应时间变成了4 s;
|
||||
- **系统资源的占用率变高了**。比如,上一版本中,平均CPU占用率是15%,但是在最新的被测版本中平均CPU占用率变成了30%;
|
||||
- **网络带宽的使用量变高了**。比如,上一版本中,发送总字节数是20 MB,接收总字节数是200 MB,但是在最新的被测版本中发送总字节数变成了25 MB,接收总字节数变成了250 MB。
|
||||
|
||||
这里需要注意的是,这些“恶化”趋势的前提是:完全相同的环境以及测试负载。不同“恶化”指标的排查,有不同的方法。我以最常见的事务响应时间变慢为例,和你说明一下排查方法。
|
||||
|
||||
假设,通过性能基准测试的比较结果得知,用户登录的响应时间从2 s变成了4 s。
|
||||
|
||||
那么,我们首先要做的是验证在单用户的情况下,是否会出现响应时间变长的问题。具体做法是,将用户登录的虚拟用户脚本单独拿出来,建立一个单用户运行的性能测试场景并执行,观察用户登录的响应时间是否变慢。
|
||||
|
||||
如果变慢了,就说明这是单用户登录场景就可重现的性能问题,后续的处理也相对简单了。解决方法是:分析单用户登录的后端日志文件,看看完成登录操作的时间具体都花在了哪些步骤上,相比之前哪些步骤花费的时间变长了,或者是多出了哪些额外的步骤。
|
||||
|
||||
如果没有变慢,则说明我们必须尝试在有压力的情况下重现这个性能问题。为此,我们要基于用户登录的虚拟用户脚本构建并发测试的场景,但是我们并不清楚在这个场景设计中到底应该采用多少并发用户、加入多长的思考时间。这时,通常的做法是,直接采用性能基准测试中的并发用户数和思考时间,去尝试重现问题。如果无法重现,我们可以适当地逐步加大测试负载,并观察响应时间的变化趋势。
|
||||
|
||||
**这里需要注意的是,千万不要使用过大的测试负载**。因为测试负载过大的话,系统资源也会成为性能瓶颈,一定会使响应时间变长。但这时,响应时间变长主要是由资源瓶颈造成的,而不是你开始要找的那个原因。
|
||||
|
||||
如果此时可以重现问题,那就可以进一步去分析并发场景下,用户登录操作的时间切片,找到具体的原因。如果此时还是不能重现问题的话,情况就比较复杂了,也就是登录操作的性能可能和其他的业务操作存在依赖,或者某种资源竞争关系,这就要具体问题具体分析了。
|
||||
|
||||
一般来说,当定位到性能“恶化”的原因并修复后,我们还会再执行一轮性能基准测试,以确保系统对外发布前的性能基准测试指标没有“变坏”。可以说,**通过对每个预发布版本的性能基准测试,我们可以保证新发布系统的整体性能不会下降,这也就是性能基准测试最终要达到的目的。**
|
||||
|
||||
很多大型的传统软件公司都有专门的性能测试团队,这个团队会建立标准的性能基准测试场景,并把性能基准测试的结果作为产品是否可以发布的依据之一。比如,我曾工作过的HP软件,就由性能测试卓越中心负责维护、执行性能基准测试,并分析测试结果。
|
||||
|
||||
从性能基准测试的设计角度来看,你需要特别注意以下三点:
|
||||
|
||||
<li>
|
||||
性能基准测试中虚拟用户脚本的选择以及配比,需要尽可能地匹配实际的负载情况;
|
||||
</li>
|
||||
<li>
|
||||
总体的负载设计不宜过高,通常被测系统的各类占用率指标需要控制在30%以内,尽量避免由于资源瓶颈引入的操作延时;
|
||||
</li>
|
||||
<li>
|
||||
每次性能基准测试前,一般需要对系统资源以及网络资源做一轮快速的基准测试,以保证每次被测环境的一致性,同时也要保证数据库的数据量在同一个级别上。总之,你需要采用一切可能的手段,来确保多次性能基准测试之间的环境一致性。
|
||||
</li>
|
||||
|
||||
## 稳定性测试
|
||||
|
||||
稳定性测试,又称可靠性测试,主要是通过长时间(7*24小时)模拟被测系统的测试负载,来观察系统在长期运行过程中是否有潜在的问题。通过对系统指标的监控,稳定性测试可以发现诸如内存泄漏、资源非法占用等问题。
|
||||
|
||||
很多企业级的服务器端产品,在发布前往往都要进行稳定性测试。稳定性测试,通常直接采用性能基准测试中的虚拟用户脚本,但是性能测试场景的设计和性能基准测试场景会有很大不同:
|
||||
|
||||
>
|
||||
一般是采用“波浪式”的测试负载,比如先逐渐加大测试负载,在高负载情况下持续10多个小时,然后再逐渐降低负载,这样就构成了一个“波浪”,整个稳定性测试将由很多个这样的波浪连续组成。
|
||||
|
||||
|
||||
稳定性测试成功完成的标志,主要有以下三项:
|
||||
|
||||
- 系统资源的所有监控指标不存在“不可逆转”的上升趋势;
|
||||
- 事务的响应时间不存在逐渐变慢的趋势;
|
||||
- 事务的错误率不超过1%。
|
||||
|
||||
实际工程项目中,由于稳定性测试执行的时间成本很高,往往需要花费3~7天的时间,所以我们一般是在其他所有测试都已经完成,并且所有问题都已经修复之后才开始稳定性测试。
|
||||
|
||||
另外,有些企业为了缩短稳定性测试的执行时间,往往还会采用“时间轴压缩”的方法,具体的做法就是:在加大测试负载的前提下,适当缩短每个“波浪”的时间,从而减少整体的测试执行时间。
|
||||
|
||||
最后,需要强调的一点是,**虽然很多时候,尤其是产品版本已经逐渐走向成熟期时,稳定性测试并不会发现问题,但是千万不要小看稳定性测试带来的价值**。因为稳定性测试一旦发现问题,那么这些问题都是很严重而且非常隐蔽的大问题。
|
||||
|
||||
所以,很多大型的企业级软件企业都会执行严格的稳定性测试,并把稳定性测试的结果作为产品是否可以发布的硬性要求。比如,我曾经工作过的HP软件研发中心,它每次产品发布前都会由专门的性能测试团队完成严格的稳定性测试,并以此来决定是否要发布这个产品。
|
||||
|
||||
## 并发测试
|
||||
|
||||
并发测试,是在高并发情况下验证单一业务功能的正确性以及性能的测试手段。高并发测试一般使用思考时间为零的虚拟用户脚本来发起具有“集合点”的测试。
|
||||
|
||||
“集合点”的概念,我已经在[《聊聊性能测试的基本方法与应用领域》](https://time.geekbang.org/column/article/14832)中解释过了。如果你不清楚的话,可以再回顾一下这篇文章。如果你还有不理解的地方,也欢迎和我留言讨论。
|
||||
|
||||
并发测试,往往被当作功能测试的补充,主要用于发现诸如多线程、资源竞争、资源死锁之类的错误。要执行并发测试,就需要加入“集合点”,所以往往需要修改虚拟用户脚本。
|
||||
|
||||
加入“集合点”一般有两种做法:
|
||||
|
||||
<li>
|
||||
在虚拟用户脚本的录制过程中直接添加;
|
||||
</li>
|
||||
<li>
|
||||
在虚拟用户脚本中,通过加入lr_rendezvous()函数添加。
|
||||
</li>
|
||||
|
||||
## 容量规划测试
|
||||
|
||||
容量规划测试,是为了完成容量规划而设计执行的测试。
|
||||
|
||||
那什么是容量规划呢?所谓容量规划,是软件产品为满足用户目标负载而调整自身生产能力的过程。
|
||||
|
||||
所以,**容量规划的主要目的是,解决当系统负载将要达到极限处理能力时,我们应该如何通过垂直扩展(增加单机的硬件资源)和水平扩展(增加集群中的机器数量)增加系统整体的负载处理能力的问题。**
|
||||
|
||||
目前来讲,容量规划的主要方法是基于水平扩展。但是,具体应该增加多少机器,以及增加后系统的负载处理能力是否会线性增长,这些问题都需要通过容量规划测试进行验证。
|
||||
|
||||
那么,容量规划测试具体要怎么做呢?
|
||||
|
||||
我们可以使用性能基准测试中的虚拟用户脚本,以及各个业务操作脚本的百分比,压测单机部署的被测系统。我们会采用人工的方式不断增加测试负载直到单机系统的吞吐量指标到达临界值,由此就可以知道单台机器的处理能力。
|
||||
|
||||
**理论上讲,整个集群的处理能力将等于单台机器的处理能力乘以集群的机器数,但是实际情况并不是这样**。实际的集群整体处理能力一定小于这个值,但具体小多少就是要靠实际的测试验证了。
|
||||
|
||||
理想的状态是,集群整体的处理能力能够随着集群机器数量的增长呈线性增长。但是,随着机器数量的不断增长,总会在达到某个临界值之后,集群的整体处理能力不再继续呈线性增长。这个临界值是多少,我们也需要通过容量规划测试找出来了。
|
||||
|
||||
另外,容量规划测试的测试结果还可以被用作系统容量设计的依据。比如,企业级软件产品的目标用户规模通常是可以预估的,那么我们就可以通过这些预估的系统负载计算出软件部署的集群规模,并且可以在具体实施后通过容量测试的方式进行验证。
|
||||
|
||||
## 总结
|
||||
|
||||
在前面的两篇文章中,我和你分享了如何基于LoadRunner开展性能测试,但是并没有具体去讲解要开展哪些类型的性能测试。所以,今天我就挑选了最重要的四类性能测试方法,和你分享如何在实际项目中完成这些测试,确保软件的性能。
|
||||
|
||||
- 性能基准测试,可以保证新发布系统的整体性能不会下降;
|
||||
- 稳定性测试,主要通过长时间模拟被测系统的测试负载,观察系统在长期运行过程是否存在问题;
|
||||
- 并发测试,往往被当作功能测试的补充去发现多线程、资源竞争、资源死锁之类的问题。
|
||||
- 容量规划测试,主要用于确定给定负载下的系统集群规模,其测试结果可以被用作系统容量设计的依据。
|
||||
|
||||
## 思考题
|
||||
|
||||
你所在企业,还会采用哪些性能测试方法,又是如何展开具体的测试工作的呢?
|
||||
|
||||
感谢你的收听,欢迎你给我留言。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user