本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/580d914e07b7fc1c26a0cf7c
随着部门业务的拓展,我们有了很多性能测试的机会,但在实战中,慢慢发现,我们对性能测试的理解并不如自己想的那么清晰,对基本概念和理论的混淆,导致对测试结果的不够自信,测试过程也常会面临质疑。
所以这一次,我们不说性能测试怎么做,先一起梳理下性能测试的基本理论,分析这些理论如何在压测工具中产生影响。
描述一个系统的性能从来不是一句话或是一个数值的事。
在IEEE的定义中:性能是系统或组件在给定约束中实现的指定功能的程度,诸如速度、正确性、内存使用等。
所以性能测试报告中,对系统性能的描述应该是多方面的,如:执行效率、稳定性、兼容行、可靠性、可扩展性容量等;其中,执行效率通过并发用户数、响应时间、吞吐量、成功率、资源消耗综合体现。
性能测试有:负载测试、压力测试、配置测试、并发测试、容量测试、稳定性测试。
其中,并发测试是测试多个用户同时访问同一个应用、同一个模块或者数据记录时是否存在死锁或者其他性能问题。
在实际的压测中,我们基本上都是设置多个并发,再进行负载测试、压力测试等,因为现实中,我们的系统就是面对多个用户的同时使用,并且,并发用户的数量,直接影响着系统资源的消耗,例如cpu、mem、网络连接、带宽,甚至于系统内部逻辑。
并发怎么看?
所谓并发,它的特点是“并行”和“同时”。
LoadRuner的并发很好理解,就是虚拟用户数。因为LR有个集合点,可以在所有虚拟用户初始化且到达集合点后,再一起执行后续操作,从而达到同时且并行的效果。
但目前在后台性能测试,我们自己开发的工具大多不带集合点功能,这时候使用者对并发的理解就会有点混乱。
下面以长连接压测为例,压力产生思路主要有以下三种:
(1)一个单进程、单线程工具,启动一次连续发m个包。这种其实属于单并发,请求串是一个接一个串行到达压测对象,一般都要再简单封装下,类似多进程并发:
for ((i=1; i<=$n; i++))
do
{
./send_${i} $msg $loop_num
}
done
注意这样还是串行执行,下面这种才能起到并发的作用。
for ((i=1; i<=$n; i++))
do
{
./send_${i} $msg $loop_num
}&
done
wait
(2)多线程模拟多客户模式。配置多个线程,一个线程发起一个连接到达压测对象,n个线程就有n个连接。
(3)连接池模式。线程与连接数并不一一对应,维持压测工具到被压对象的连接数不变,线程们从连接池挑选空闲的连接持续发送请求。(个人感觉和线程池模式很类似!)
以上三种情况,假设所有线程极致同步且系统性能足够,那么同一时间内(或者说同一瞬间),应该是有等同线程个数的请求同时到达系统,并同时被处理完再一起返回,此时线程就是并发,线程数就是并发数,这里理解应该没有问题。
但实际上,所有的并发不可能做到完全同步,压测过程中由于各种影响,比如:各线程初始化速度不一样,连接数不够,处理速度不一样等,导致在并行节奏上相互有了偏差, 这种现象在系统接近性能瓶颈时,会更加突出。所以会有同学疑问,这还能叫“并发”吗? 这里引入“狭义并发”和“广义并发”的概念。
广义的并发实际上是在一个时间内操作事务的虚拟用户,而狭义的并发指的是单位时间内向系统发起请求的虚拟用户,前者是“存在”,后者是“请求”,勿容置疑,压力不仅仅受成功发出请求的用户带来的压力,同时也受“存在”的用户影响。
这样看来,工具中的线程数设置,更偏像是广义并发,代表着在压测时间段内虚拟用户总数,这也是并发原始值。而在后续的压测过程中,在单位时间内,并发数可能会动态变化,这里是狭义并发。
当工具产生的压力远未到系统性能瓶颈时,理论上,狭义并发=广义并发=工具线程数;当压力增加,系统响应时间增长,部分线程的请求处理正常,部分线程可能请求超时,那么同一单位时间内,同时向系统发起请求的用户数就不等于线程数了。
那么我们如何实时掌握压测过程中可能变化的并发?
《Method for Estimating the Number of Concurrent Users》一文介绍了一种并发估算法(网上有很多相关资料,这里不再累述):
C:并发
n:压测时间段内所有的请求数
L:平均响应时间
T:压测总时长
这里注意:L(平均响应时间)≠ T(总时长)/ n(总请求)
压力就是并发在单位时间内对压测对象的请求数。在我们的压测工具中,有一个配置项专门用来设置压力,可能是所有线程产生的总压力,也可能是单个线程产生的压力。
有些同学会在这里纳闷,为什么我设置了发送10w笔/s的请求,系统吞吐量的计算只有1w笔/s,是不是工具有问题?这里是因为混淆了压力和性能。
压力不等于性能,压力只是检验性能的一种手段。对一个性能良好的系统,在一定的压力下应该可以保持正常运转,如果超过负荷,则应该分流或化解压力,这也是我们需要检验的。
例如:100个并发,1s内发送1w笔请求,如果系统的吞吐量计算大于或等于1w笔/s,说明系统承受住100个并发,1w/s的压力,我们可以增加压力继续测试,直到出现性能拐点;如果系统的吞吐量计算是5k笔/s,则说明,如果我们需要系统应付100个并发,1w/s的压力,解决方案要么提升系统性能一倍,要么扩容一台分流压力。
要特别注意:压力是由工具制造,工具的最大性能决定施加的最大压力。我们在测试过程中曾经遇到压测系统还没到极限,工具已经到瓶颈的情况,这时候得到的压测数据是错误的。
我们在压测工具制作中,一直存在一个争议——吞吐量的计算。
在性能测试中,吞吐量的计算有两种常见的公式:
公式1: 吞吐量=并发数/平均响应时间
公式2: 吞吐量=请求总数/总时长
公式1、2大家应该都接触过,虽然看上去不一样,其实理论上都是ok的。
首先我们可以从C = nL / T 推导:
并发 = 请求总数*平均响应时间 / 总时长
=》并发 / 平均响应时间 = 请求总数 / 总时长
=》公式1 = 公式2
然后我们构建三组模型进一步论证:
第一组模型
一共有4个线程,同时发了4笔请求,其中3笔耗时1s,一笔耗时2s,整个过程一共耗时2s。
公式1:
平均响应时间 = (1+1+1+2)/ 4= 1.25s ;
并发 = nL/T =4*1.25/2 =2.5
吞吐量 = 2.5 / 1.25 = 2 笔/s
公式2:
吞吐量 = 总笔数/总耗时 = 4/2= 2 笔/s
第二组模型
一共有4个线程,同时发了4笔请求,4笔请求耗时均为1s,1s内全部发送完毕。
公式1:
平均响应时间 = (1+1+1+1)/ 4= 1s
并发 = nL/T =4*1/1 =4
吞吐量 = 4 / 1= 4 笔/s
公式2:
吞吐量 = 总笔数/总耗时 = 4 / 1= 4 笔/s
第三组模型
一共有4个线程,4笔请求耗时均为1s,但线程发送出现不同步现象,一共持续1.5s完成全部:
公式1:
平均响应时间 = (1+1+1+1)/ 4= 1s
并发 = nL/T =4*1/1 =4
吞吐量 = 4 / 1.5= 2.67 笔/s
公式2:
吞吐量 = 总笔数/总耗时 = 4 / 1.5 = 2.67 笔/s
从我们构建的模型上看,两个公式计算的结果是相等的。但是,这种平衡是建立在并发稳定的基础上,并发如果变化,结果就会有差异。下面我们看一组真实的压测数据
从上图中看出,实际压测时,两个公式还是会有些微差别,这就是因为我们本来预想并发应该=工具线程数,但在压测过程中,实际并发发生了变化,我们再反推下实际的并发数
计算出的实际并发确实稍低于工具线程数。
在单接口压测时,我们用“请求总数/总时长”得到吞吐量;然后再用“吞吐量/平均响应时间”得到实际并发,此举可用来观察系统实际承受的并发;
在多接口压测时,由于短板效应,同一个流程中的所有接口获得的请求总数和总时长都一样,显然“请求总数/总时长”计算各个子接口的吞吐量不合适,所以改用“并发/平均响应时间”,其中的并发数应在压测工具中埋点统计,不可简单使用工具线程数。
在性能测试平台的开发中,为了测试结果更接近现实,我们在吞吐量计算上改过三个版本,小伙伴们也有过几次激烈的讨论,正是对这种小细节的不断纠缠,我们对性能测试的认识也在不断刷新,原本以为正确的地方被颠覆,不理解的环节逐渐清晰,越琢磨越会发现性能测试的有趣。
如文中观点有理解不到位的地方,欢迎大家一起探讨指正。
性能测试解惑之并发压力
http://www.cnblogs.com/pohome/articles/2073283.html软件性能测试流程简介
http://wenku.baidu.com/link?url=9vfFqnNCsJ3Nv0cAl8_nb9SefIN17TFskt02E0yu75Zk6XVcHEz21rfrKrSfIFi7WhSqOWjsvz1k9fnVZ8SNn1GFbDpzjIzOWjBID1NfmOC软件性能设计与评价
http://www.doc88.com/p-331430307121.htmlMethod for Estimating the Number of Concurrent Users
http://wenku.baidu.com/link?url=w6eahwDiL_7Fyv5ekbpDGj946jICLtWyc7PphU63t7Mu8u84jdlGIMJSpBaxySUH49bU648a-1Y_xap9iSR4vuO1bMdYBOLhYdntDzyrRB7