性能测试工具 JMeter100 个线程竟然只模拟出 1 个并发

测试开发体系 · 2020年11月10日 · 最后由 爱吃米饭 回复于 2020年11月20日 · 6966 次阅读

线程组,是说到 JMeter 会第一时间想到的东西,也是我认为 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 的线程组编辑区如下:

Name

名称,最好有业务意义。

Comments

注释,可以为空。

Action to be taken after a Sampler error

线程组中某个线程的请求出错后,该怎么处理。有 5 个选项,Continue,Start Next Thread Loop,Stop Thread,Stop Test,Stop Test Now。

例如,假设有 1 个线程,包括 2 个取样器,迭代执行 2 次:

Continue

请求出错后,线程继续运行。

为什么要继续运行呢?我们在大量用户并发时,服务器偶尔响应错误是正常现象,比如服务器由于性能问题 500,此时出错我们正好要记录下来,作为有性能问题的依据。但是仍然可以继续请求进行重试,说不定服务器又能访问了,这样可以算出错误率

比如,登录失败了,那么下单的操作由于登录失败,也会跟着失败。

默认选择此项,保证足够的并发压力

Start Next Thread Loop

如果出错,则同一线程中的余下请求将不再执行,直接重新开始新一轮迭代。

比如,登录失败了,那么下单的操作将不再执行,重新开始。

如果想减少关联请求报错,可以选择此项。

Stop Thread

一般不会设置此项,它指的是请求失败后,停止当前线程,不再执行。这样会导致运行线程越来越少,最后负载不够,对服务器的压力不够,测试结果不具参考性。

Stop Test

如果某一线程的某一请求失败了,停止所有线程测试。

但是每个线程还是会执行完当前迭代后再停止。相当于 Continue 到当前迭代结束。

比如线程 1 正好执行到登录,有其他线程出错了,线程 1 也会执行完下单操作才会停止。

Stop Test Now

如果有线程的请求失败了,立即停止所有线程,不再执行。

Thread Properties

Number of Threads (users)

运行的线程数设置,一个线程对应一个模拟用户。

Ramp-up period (seconds)

所有线程在多长时间内开始运行,单位是秒。

比如我们设置线程数为 50,此处设置 10 秒,那么每秒就会启动 50 / 10,5 个线程。如果设置为 0 秒,则 50 个线程会立刻启动。如果设置为 100 秒,就会每隔 100 / 50, 2 秒 启动 1 个线程。

Ramp-up period 的大小问题

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 个线程执行完开始新的迭代,从而形成梯度递增的并发请求。

Loop Count

迭代次数。可以填写数字指定迭代次数。也可以勾选 Infinite,表示无限迭代,一直运行到测试停止或异常崩溃。

Same user on each iteration

在 JMeter 中,user 就是线程,此选项的意思是说每个迭代都用相同的线程。

这个得从老版本讲起,在以前 3.x 和 4.x 版本的 JMeter 中,是没有这个选项的。创建好 1 个线程后,每次迭代都是用这个线程,直到测试结束。它的影响就是,比如登录,加了 HTTP Cookie 管理器以后,单个线程多次迭代(注意不是多个线程哦)登录用的都是相同的 Cookie。

5.x 版本加入了这个选项,可以控制每次迭代是否创建新的线程。同时在 HTTP Cookie 管理器也增加了一个选项,控制是否清除旧 Cookie:

默认这个 Same user on each iteration 的选项是勾选的。因为销毁和创建线程本身就会占用资源,可能会影响性能测试结果。

Delay Thread creation until needed

跟 JVM 创建线程时机有关,实际运用勾不勾选都不影响测试结果,保持默认就好。

Specify Thread lifetime

Duration

持续时间,单位秒。Loop Count 勾选了 Infinite,才有作用。

Startup delay

启动延迟,单位秒。延迟到时间后再运行线程。

简单回顾

本文首先解析了 JMeter 为什么能做性能测试的原因,接着对线程组编辑区的选择进行了讲解,重点梳理了 Ramp-up period 的大小问题。此外,JMeter Plugins 还提供了两个线程组元件 Ultimate Thread Group 与 Stepping Thread Group,以满足浪涌(波涛状,多个波峰)的场景。笔者水平有限,若有错误,请指正。

参考资料:1.《全栈性能测试修炼宝典 JMeter 实战》

2.https://www.cnblogs.com/hjhsysu/p/9189897.html

共收到 20 条回复 时间 点赞

blazemeter 提供的那几个线程组插件,数据全是错的(跟 jmeter 自带的 threadgroup 相比),博主好好测一测。。。。。。

杨杰 回复

你这说的啥?没用过 blazemeter 啊

楼主好,关于线程启动这里有个疑问,原文如下:

比如我们设置线程数为 50,此处设置 10 秒,那么每秒就会启动 50 / 10,5 个线程。如果设置为 0 秒,则 50 个线程会立刻启动。如果设置为 100 秒,就会每隔 100 / 50, 2 秒 启动 1 个线程。

但是:
我尝试过 0 秒启动 10 个线程,循环一次,观测发现并不是 10 个都会立刻启动,而是有些线程还没来得及启动,请求就结束了。所以 0 秒代表立刻启动全部线程这个说法,是不是不准确呢?
理解的不对的话还请多多指正

爱吃米饭 回复

“有些线程还没来得及启动”
这个是怎么看不来的哇?我也试了,一运行右上角那就直接是 10/10 了。

我是在本地起了一个服务,直接看的服务端打进来的请求数量。

爱吃米饭 回复

具体现象是?

我刚刚又跑了一下,给您截图看一下:

然后这是我服务抓到的请求数量:

如果是通过 15:45:58 这一秒的请求数没有 10 个,来判断的话,就不一定了。因为从线程发出请求,到服务器响应,并在 console 打印出日志,可能会有时延。

jmeter 左上角也没有运行完成的数量呢;
再者就是,时延的话,应该最终也会显示在 log 里面吧?但是看日志并没有再次更新了🎃

爱吃米饭 回复

你加个 View Result Tree 看看哇,意思这 10 个线程只请求了截图这几个?我看有报错的。首先排除脚本本身问题,保证能有 10 个请求成功。

你是对的,我看了一下,确实有报错的。
请问 报错的原因是因为承受不了这么多的并发吗?

爱吃米饭 回复

不一定,有可能是你本地机器性能导致承受不了并发,也有可能是程序错误如死锁等,需要结合程序逻辑数据和系统资源占用来分析。

爱吃米饭 回复

你说的这个是对的,并不会立马启动 10 个线程,线程启动本来就会有先后,jmeter 的机制也是这样,要验证 10 个线程启动需要设置集合点确认

你的意思是,即使设置了 10 个线程在 0 秒启动,仍然不会并发,对吗?
另外请教一下,你说的集合点是什么意思呢?

说法不严谨。
Java 线程状态如下:

JMeter 有个 Delay Thread creation until needed 选项,默认线程启动就运行跑 Sampler(RUNNING),勾选后线程只启动(NEW)。
集合点是定时器的一种,是让线程阻塞等待,跟启动没有关系。

请教一下,如果我想设置并发,是不是这个选项: Delay Thread creation until needed 设置足够长时间,长到所有线程都 new 出来了,然后再统一运行,这样可以吗?
这样的效果,是不是和所有线程 0 秒启动的效果一样呢?

爱吃米饭 回复

不用太纠结启动了。
你如果想要实现同一时刻多个线程一起发请求,设置个 同步定时器 就可以了。

测试并发不就是为了同一时刻多个线程一起发送请求吗?
既然有同步定时器可以保证并发,那不懂为什么还需要计算并发的时序图,比如下面这个:

小白真心求教

爱吃米饭 回复

从某个时间点来看,服务器对每个线程请求的处理,不一定都是相同的进度,但是每个线程都给服务器造成了处理压力。
所以当线程都启动以后,只要保证这些线程在持续不断给服务器施压就可以了。
如果都按照定时器来保证并发,那么阻塞等待的耗时会比较多。一般给需要的 Sampler 添加同步定时器就可以了,而且可以设置达到多少个线程为一组进行同时请求,比如 100 个线程,每满 20 个线程同时请求。

看起来同步定时器是个好东西,我去研究一下,谢谢你

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册