引言
很多做性能测试的同学都问过我这样一个问题:你说性能测试的重点是什么?
我的回答很简单:瓶颈分析与问题定位。
在性能项目的整个周期,不管是脚本设计、脚本编写还是脚本执行,都还算简单。
难点在于如何定位瓶颈、分析瓶颈、解决瓶颈。
如果你不会性能分析,脚本设计得再好,脚本编写得再完美,分析不出问题所在,那都是白白浪费时间。
所以,这一讲,我们来学习:如何进行性能分析,学会了性能分析的思路,才能定位问题、分析问题,从而解决问题。
在性能项目中,我总结的性能分析思路,分5个模块,即性能分析5部曲,如下:
1、判断性能瓶颈
2、线程递增策略
3、性能衰减过程
4、拆分响应时间
5、构建分析决策tree
接下来,我就对这5部曲进行一一解释。
判断性能瓶颈
如何判断性能瓶颈,在整个性能测试过程中,这是让性能测试工程最苦恼的事情。如果无法准确的定位到性能瓶颈,那么对开发的协助能力就有限,从而无法快速的解决性能瓶颈。
而分析性能瓶颈,也是排查解决问题的第一步。如何进行问题分析,我先上一张图:
通过这张图,我们很直观的知道:这是一个很明显阶梯式增加的场景。
但是,请思考一下,我们是否能判断出拐点在哪呢(在性能测试过程中,都是要先找拐点,再定位问题)?
这时候肯定就会有人说在1300左右, 也有人认为在1500左右,还有人会说这明明就是在2000出现的拐点。
别着急,我们再看这张TPS图对应的ResponseTime(后面简称为RT)图:
看到RT图,是不是就会有人说在4.5就出现了拐点。其实以上这些对拐点的判断,都不合理(不能说完全不正确)。
如果要对TPS的增加控制非常准确的话,就需要找到TPS在增加时,那个明显而清晰的弧度,而不那个明显而清晰的拐点,这一定要注意,也是一定要记住。
但是,通过TPS图和RT图,我们还是可以判断出瓶颈在第二个压力阶段就已经出现了。
原因
响应时间增加了,TPS却没有增加的那么多,到第三阶梯时,TPS增加的就更少了,响应时间还在不断的增加。
所以,性能瓶颈就在不断的加剧,而越往后面的阶梯,这种现象就越明显,直到系统垮掉或手动停止掉。
根据上面的现象,我们的判断结果:
-
系统有瓶颈
-
瓶颈和压力有关
-
压力呈阶梯型,而且增长幅度在不断衰减
我们再来看一张图:
通过这个图,是不是感觉系统系统有瓶颈了。
但是,思考一个问题:瓶颈点是否跟压力大小有关呢?
答案:肯定不是跟压力大小有关。
因为通过图可以看出:
-
这个问题是很有规律的;
-
TPS周期性的出现降低,并且最大的TPS也都差不多是一致的。
所以,即使压力降低,最多只是降低最大的TPS水位,这种情况只是让问题出现的更晚一点,但不会不出现的。
根据以上综述,我通过一个示意图来表示TPS的衰减过程,如下:
通过上图,我们可以总结出两点内容,即:
-
随着用户数的增加,响应时间在缓慢增加;
-
TPS增加幅度在变缓,直到逐渐变平。
在这种趋势图中,我们无法看到明确的拐点,但我们却可以得出明确的结论:系统有瓶颈。
而系统的瓶颈又在哪里呢?通过这个趋势图,我们无法判定。
所以,通过TPS曲线图,我们可以知道:
-
当前测试系统是否有瓶颈;
-
瓶颈和压力是否有关系。
再强调一次
判断瓶颈是否与压力有关,就看随着压力的增加,TPS的变化情况,如果随着压力的增加,TPS逐渐变缓,直到拉平,那么就是有关系,否则,就跟压力没有关系。
这一点,一定要牢记,这是判断压力与瓶颈关系最直接的方式。
线程递增策略
接下来,我们就来说一说线程递增策略。
首先,我直接通过两个场景的执行结果(线程图、TPS图、响应时间图)进行对比:
场景一
线程图
TPS图
响应时间图,如下:
响应时间图
场景二
线程图
TPS图
响应时间图
场景一与场景二的对比情况,表格统计如下:
根据这两个场景的对比情况,可以直观的看出:虽然两个场景的TPS都达到了400,但是由于递增策略的不同(场景一为一次性并发500, 场景二为 连续逐步递增直到500),故产生的响应时间就不同。
这两个场景虽然错误率都为0,但是场景一却不符合真实的业务场景(如果你说场景一是为秒杀场景设置,那我只能稍后再解释),原因如下:
1、正常情况响应时间是从低到高的,但是在场景一却恰恰相反;
2、线程数是需要连续递增的,在场景一中却没有;
3、虽然两个场景的TPS都达到400,但是场景一的线程数却是500,而场景二的线程数40就达到了。
所以,我们可以总结出:对于一个系统来说,如果是仅仅改变压力策略(其他环境、资源等都不变),那么系统最大TPS的上限值就是固定的。
我们再回来说场景一的一次性发送500线程并发的问题:在我们常规认知里,一直觉得秒杀场景就是要最大的并发线程数,其实这种情况,并不合理。
因为即使线程数增加的再多,对于已经达到TPS上限的系统来说,除了RT不断的增加,其他没有任何意义。
敲黑板
我们描述系统的容量是用系统当前处理业务量,而不是线程数。
所以,对于场景中线程递增策略,我们要做到以下几点:
1、场景中的线程数一定是要连续的、递增的;
2、场景中的线程递增一定要跟TPS的递增比例有关系,而不是直接达到上限值;
3、针对秒杀类场景,我们前期需要做好系统预热,在预热之后,再对线程数突然增加而产生的压力,就在可处理的范围内。
性能衰减过程
在前两节中,我们了解了如何判断性能瓶颈,又知道了如何进行场景线程递增策略,那么,接下来我们就要掌握在性能测试过程中,如何判断性能衰减过程。
同样,我先上一个压力工具测试结果图:
针对上面的压力结果,我们来做三次计算:
1、当线程数达到24时,TPS为1810.6,即每秒发出的请求数为1810.6 / 24 ≈ 75.44;
2、当线程数达到72时,TPS为4375.1,即每秒发出的请求数为4375.1 / 72 ≈ 60.77;
3、当线程数达到137时,TPS为5034,即每秒发出的请求数为5034 / 137 ≈ 36.74。
最后,我们可以得出:随着线程数的增加,每秒的请求数却在变少,但是TPS却是在增加。
但是,我们仔细看这个结果可以发现,在整个压力过程中,性能是在不断的衰减的。
这个时候,你可能会说:你不是说了,线程数不断的增加,TPS也在不断的增加,怎么能说性能在衰减呢?
我再把压测结果对应的RT、TPS、线程数、每秒请求数图都展示出来,你可能就能明白了。
这个时候,我们在仔细看统计图,可以发现每秒的请求数下降到56左右时候,TPS就达到了上限值(即5000),再继续增加线程数,最后的结果只是响应时间不断的增加而已。
当然, 这里还是需要你记住:只要“线程/秒”的TPS开始变少,就意味着性能瓶颈出现了。但是,并不是说出现瓶颈了,服务器的处理能力就变差了,而是TPS仍然会上升,在性能不断的进行衰减过程中,TPS会达到上限值。
如果按照这样的推理,那么是不是应该在性能衰减到TPS达到最大值时,停止脚本执行呢?
这个并不绝对,因为是否停止继续执行,需要取决于我们的测试目的:
1、如果我们只想测试最大TPS上限值,而这个时候,就可以停止;
2、如果想测试系统最大运行时间,那么这个时候,就不能停止。
当然,还有一个场景,也是不能停止的,这里我要单独例举:如果我们想更精准的找到性能瓶颈,这个时候也不能停,因为我们要延长响应时间,从而拆分响应时间,找到性能瓶颈。
这就进入到了接下来我要说的:拆分响应时间。
拆分响应时间
在性能工程中,性能分析是必不可少的,而在性能分析中,拆分响应时间又是必不可少的。
在整个性能场景中,只要达到系统瓶颈,不管再怎么增加压力,最后肯定会导致响应时间的增加,直到出现Timeout。
在压力工具(Jmeter/Loadrunner/Loust……)中看到的响应时间,都是经过后端的每一个系统的。
这个时候,我们肯定会问到,如何能准确的判断出瓶颈点呢?
这就是判断的难点,但是也不要着急,因为没有解决不了的问题。
我先上一张图,来看一下压力测试逻辑:
上图,就是一个最简单的压力测试逻辑图,一个应用、一个DB,最后竟然还是拆出了8个时间段,而这还没有对压力工具自己消耗的时间进行拆分。
俗话说:理想总是丰满的,现实却是悲伤的。在实际的场景中,如果是内网,那么就是下面这个逻辑了:
而在这样的压力逻辑图,依然可以拆出8个时间段,类似于上个拆分响应时间时间的方法,这里就不拆分了。
当然了,还有第三种情况:
这种情况,我们可以更直观更清晰的拆分响应时间的。
拆分步骤/方法如下:
1、先去Nginx上查看时间
2、再去Tomcat上查看时间
3、最后查看MySQL的消耗
4、通过花费时间进行对比,就可以分析出是哪个环节的瓶颈了
这就是拆分响应时间的步骤,一步一步的来拆分,如果拆分的不准确,或者盲目的拆分时间,最后就无法准确的构建分析决策tree。
为什么这么说呢, 接着往下看。
构建分析决策tree
关于性能分析决策tree的重要性,我在线上/线下培训时、全链路压测专栏、亦或者在工作中都有提说到。
因为性能分析决策tree是性能分析环节中不可缺少的一环节。性能分析决策tree是对架构的梳理,是对系统的梳理,是对问题的梳理,是对分析思路的梳理。
或许你会问,性能分析决策tree有这么厉害吗?我把性能分析决策tree流程图画出来,你就知道到底厉不厉害了:
通过上图,我们可以直接看到,只要知道TPS、RT和错误率三条曲线,就可以明确的判断出性能瓶颈是否存在。
再通过性能分析决策tree,结合各个监控,就会知道是哪个环节出现的问题。这里,我在针对操作系统进行详细拆分,其余的这里就不进行拆分了。
看到这个流程图,是不是恍然大悟,终于知道了如何对操作系统进行拆分了。但是还是的说,前提:拆分操作系统,就需要对操作系统有足够的的了解,否则你懂的……。
总结
看到这里,性能分析5部曲就讲完了。
而在这一讲中,我从 性能瓶颈的判断→线程递增的策略→性能衰减过程→响应时间的拆分→分析决策tree的构建 都进行了详细的说明。
之所以花费这么多时间与精力来写性能分析的思路,是因为性能分析在整个性能测试过程中太重要了。
如果无法分析性能问题,就无法定位到问题,从而就无法解决性能瓶颈,这都是环环相扣的,缺一不可。
同时,性能分析也是拉开性能测试工程师level的一个重要标准。
性能分析在性能测试过程中是必不可少的环节。
所以,学会性能分析,是作为性能测试工程师必须要掌握的技能。
但是在整个性能测试行情中,据我了解很多性能测试工程师都觉得只要自己会:设计脚本、执行脚本、最后再编写一个测试报告就完事了。
这是不可取了,也恰恰误导了性能测试工程师的职责。
所以,你要学会性能分析这5部曲,让自己在跟开发/需求的同学进行沟(hu)通(qia)时,可以底气十足。