线程组,是说到 JMeter 会第一时间想到的东西,也是我认为 JMeter 最难理解的知识点。因为项目让你做个压测,首先就是要考虑并发,用 JMeter 就是用多线程 来模拟多并发。但在看到线程组编辑区的时候,选项密密麻麻,无从下手呀。本篇文章就给大家介绍 JMeter 线程组的玩法。
我们虽然都知道 JMeter 使用线程在模拟用户,但是它到底是怎么模拟真实场景的?为什么它就能做性能测试?
为了解答这些疑惑,我们从最简单的登录压测讲起。假设新项目要上线了,需要做个压测,看看 100 个人同时登陆系统,性能怎么样。
我们先不用 JMeter,先用人工来做。找 100 个人,让这些人把自己的账号密码输好后,叫一声,登录!他们就一起点击登录按钮。
这样就算性能测试了么?不算。而且这样测的结果并没有参考意义。就算我们算出了此时登录接口响应时间是 0.5 s,那么这 0.5 s 也不能作为 100 个人同时登陆的响应时间。学过统计学就知道,单个样本数据是会有偏差的,在实验中需要测量多次后取平均值,才能减少误差。
然后我们用 JMeter 来做。设置 100 个线程,模拟 100 个用户,持续 5 分钟,让这 100 个线程不停的登录,产生成千上万条并发请求。假如登录比较慢或登录失败了,用户肯定会不停的点,就会造成持续不断的请求。JMeter 的线程也可以设置无限迭代来模拟这一情况。
测试结束后,再对所有的大量的样本数据,进行性能分析,得出平均响应时间、TPS、吞吐量等性能指标,以评估当前配置下系统性能情况,找到性能瓶颈,为性能优化提供依据。
这就是 JMeter 能做性能测试的原因,也是性能测试的意义。
知道了为什么,接下来讲讲怎么做。如果设置不当,有可能 100 个线程只能产生 1 个并发请求。
JMeter 的线程组编辑区如下:
名称,最好有业务意义。
注释,可以为空。
线程组中某个线程的请求出错后,该怎么处理。有 5 个选项,Continue,Start Next Thread Loop,Stop Thread,Stop Test,Stop Test Now。
例如,假设有 1 个线程,包括 2 个取样器,迭代执行 2 次:
请求出错后,线程继续运行。
为什么要继续运行呢?我们在大量用户并发时,服务器偶尔响应错误是正常现象,比如服务器由于性能问题 500,此时出错我们正好要记录下来,作为有性能问题的依据。但是仍然可以继续请求进行重试,说不定服务器又能访问了,这样可以算出错误率。
比如,登录失败了,那么下单的操作由于登录失败,也会跟着失败。
默认选择此项,保证足够的并发压力。
如果出错,则同一线程中的余下请求将不再执行,直接重新开始新一轮迭代。
比如,登录失败了,那么下单的操作将不再执行,重新开始。
如果想减少关联请求报错,可以选择此项。
一般不会设置此项,它指的是请求失败后,停止当前线程,不再执行。这样会导致运行线程越来越少,最后负载不够,对服务器的压力不够,测试结果不具参考性。
如果某一线程的某一请求失败了,停止所有线程测试。
但是每个线程还是会执行完当前迭代后再停止。相当于 Continue 到当前迭代结束。
比如线程 1 正好执行到登录,有其他线程出错了,线程 1 也会执行完下单操作才会停止。
如果有线程的请求失败了,立即停止所有线程,不再执行。
运行的线程数设置,一个线程对应一个模拟用户。
所有线程在多长时间内开始运行,单位是秒。
比如我们设置线程数为 50,此处设置 10 秒,那么每秒就会启动 50 / 10,5 个线程。如果设置为 0 秒,则 50 个线程会立刻启动。如果设置为 100 秒,就会每隔 100 / 50, 2 秒 启动 1 个线程。
Ramp-up period 的大小问题,对于初学者来说是最容易困扰的。
以下是 5 个线程依次从启动到执行退出的示意图:
红色框起来的部分才是真正 5 个线程并发请求的时间段。
假设我们设置 20 个线程,只运行 1 次迭代,看看不同的启动时间设置会有结果有何不同。
如果启动时间设置为 0,那么测试一开始就会产生 20 个并发请求,服务器万一只能承受 15 个并发,岂不是一上来就 gg 了,还测个什么呀。
如果启动时间设置为 40,那么会每隔 2 秒 启动 1 个线程。万一线程执行不到 1 秒就退出了,第 2 个线程 启动的时候,第 1 个线程已经退出了,不就是只产生了 1 个并发请求么。
那么设置成多少合适呢?我也不知道,但是结合我查阅的资料,可以给出一个参考意见。
第一步,把线程组跑 1 次(可以在线程组元件上右键选择 Validate),从聚合报告获取到吞吐量(Throughput)。
第二步,用线程数量除以吞吐量,得出启动时间。
例如,200 个线程,跑一次获取到吞吐量为 4/sec,启动时间为 200 / 4 = 50。这样设置以后,第 2 个线程启动后,刚好第 1 个线程执行完开始新的迭代,从而形成梯度递增的并发请求。
迭代次数。可以填写数字指定迭代次数。也可以勾选 Infinite,表示无限迭代,一直运行到测试停止或异常崩溃。
在 JMeter 中,user 就是线程,此选项的意思是说每个迭代都用相同的线程。
这个得从老版本讲起,在以前 3.x 和 4.x 版本的 JMeter 中,是没有这个选项的。创建好 1 个线程后,每次迭代都是用这个线程,直到测试结束。它的影响就是,比如登录,加了 HTTP Cookie 管理器以后,单个线程多次迭代(注意不是多个线程哦)登录用的都是相同的 Cookie。
5.x 版本加入了这个选项,可以控制每次迭代是否创建新的线程。同时在 HTTP Cookie 管理器也增加了一个选项,控制是否清除旧 Cookie:
默认这个 Same user on each iteration 的选项是勾选的。因为销毁和创建线程本身就会占用资源,可能会影响性能测试结果。
跟 JVM 创建线程时机有关,实际运用勾不勾选都不影响测试结果,保持默认就好。
Duration
持续时间,单位秒。Loop Count 勾选了 Infinite,才有作用。
Startup delay
启动延迟,单位秒。延迟到时间后再运行线程。
本文首先解析了 JMeter 为什么能做性能测试的原因,接着对线程组编辑区的选择进行了讲解,重点梳理了 Ramp-up period 的大小问题。此外,JMeter Plugins 还提供了两个线程组元件 Ultimate Thread Group 与 Stepping Thread Group,以满足浪涌(波涛状,多个波峰)的场景。笔者水平有限,若有错误,请指正。
参考资料:1.《全栈性能测试修炼宝典 JMeter 实战》