一、引言 很多做性能测试的同学都问过我这样一个问题:鱼哥(Carl_奕然),你说性能测试的重点是什么? 我的回答很简单:瓶颈分析与问题定位。 在性能项目的整个周期,不管是脚本设计,脚本编写还是脚本执行,都还算简单。 难点在于如何定位瓶颈,分析瓶颈,解决瓶颈。 如果你不会性能分析,脚本设计的再好,脚本编写的再完美,分析不出问题所在,那都是白白浪费时间。 所以,这一讲,我们来学习:如何进行性能分析,学会了性能分析的思路,才能定位问题,分析问题,从而解决问题。 在性能项目中,我总结的性能分析思路,分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)时,可以底气十足。 当然,由于篇幅的原因,我在性能分析决策tree中还有太多内容没有展开,尽量在后期的文章中进行说明。
|