
搞懂 jmeter 里顺序执行和并发执行这件事比很多人想象的重要。之前有位朋友遇到一个很诡异的现象他在一个线程组里从上到下摆了 5 个 HTTP 请求跑完去看查看结果树发现请求并不是老老实实按先后顺序记录的把线程数调成 10 之后看起来更像是一下子全部同时发了出去。其实这不是 Jmeter 在乱来而是它的执行模型本来就是按这个逻辑设计的。这篇文章就把这件事彻底说清楚什么时候它按顺序跑什么时候它并发跑两种模式各自的配置方法、适用场景以及我在实际项目里踩过的坑。假设你已经装好了 JmeterJDK 8 环境跑它就很稳我们把注意力全都放在脚本的执行逻辑上。适合刚接触 Jmeter 的人也适合那些脚本能跑通但对执行逻辑一直含糊的同行。1. 先分清两个维度线程组的并行与取样器的串行1.1 Jmeter 的执行模型其实就一句话Jmeter 用线程来模拟用户。多个线程等于多个虚拟用户这些线程之间是并发执行的而你在线程组里放的每一个取样器对单个线程来说又是严格串行的前一个请求发出并收到响应之后才会发起下一个请求。这个模型用生活化的比喻来理解会很直观一个厨师按菜单顺序炒菜同一家餐厅里十个厨师同时开火。你关心的是某个厨师炒菜的顺序还是十个厨师同时工作的状态这两件事完全不同但都属于 Jmeter 的执行逻辑。所以 Jmeter 里的并发本质上来自多线程而顺序来自单个线程内部的取样器队列。很多人在一个线程组里放了多个接口跑出来发现顺序不对其实是误解了默认行为——一个线程内部从来都是按顺序执行的只是多个线程之间互相穿插导致在结果树里看起来像乱序。1.2 线程组与线程组之间默认是并行的如果你在测试计划里建了三个线程组执行的时候这三个组几乎是同时开始跑的彼此之间没有任何内建的先后依赖。很多人以为先建的线程组会先跑完然后再跑下一个这是最常见的误区之一。那如果确实需要第一个组跑完、第二个组再开始怎么办Jmeter 也留了口子把预置任务放到 setUp Thread Group把清理任务放到 tearDown Thread Group。这两个特殊线程组会在普通线程组执行前和执行后运行。注意如果你建了多个 setUp 线程组它们之间依然是并发的不是排好队一个接一个。普通线程组之间想严格控制先后顺序操作起来非常别扭而且容易破坏压测的并发形态我的建议是不要硬来。先想想这个先后依赖是不是真的必须的多数情况下用 setUp 组或者直接都放进同一个线程组里按取样器顺序跑才是符合 Jmeter 模型的做法。1.3 Ramp-up 到底是什么并发不是一瞬间全部到位线程组面板里的 Ramp-up Period 是个经常被误解的参数。它的作用是在指定时间内把这批线程全部启动完毕线程启动间隔可以用一个简单公式估算启动间隔 Ramp-up 时间 ÷ 线程数。举个例子线程数 50Ramp-up 设为 10 秒那么 Jmeter 大约每 0.2 秒启动一个线程整个过程持续 10 秒。这不是说第一个 10 秒大家都在干等然后再一起发请求而是在这 10 秒内线程陆续到位先到位的线程已经开始执行脚本了。有人把 Ramp-up 当成预热时间不对。想观察系统在逐步加压下的表现可以把 Ramp-up 拉长希望快速进入稳态满并发Ramp-up 就设小一点比如 1 到 5 秒。Ramp-up 直接影响了并发压力爬坡的曲线压测报告的吞吐量波动往往和它有直接关系。1.4 循环次数决定执行轮次不决定并发数再强调一个高频混淆点线程数设为 1循环次数设为 100这只是同一个虚拟用户连续操作 100 次不是 100 个并发用户在同时操作。并发用户数看的是线程数而不是循环次数。这个误区在实际项目中坑过不少人。有人写测试方案说200 并发持续 10 分钟到了 Jmeter 里却把线程数写成 1、循环次数写了 1000结果跑了很久系统的压力始终只有一个用户结论完全失真。正确翻译应该是线程数 200循环次数按需设定或者直接用调度器配置 Duration 600 秒来控制持续时间。2. 顺序执行的正确姿势让接口一个接一个、数据一环扣一环2.1 什么场景需要顺序执行业务链路请求接口之间有依赖关系的场景顺序执行是硬需求。比如登录拿 Token下单用 Token 换订单号支付拿订单号去付款每一步的入参都来自上一步的返回值。这种情况下就算想并发也没法并发因为下一个请求的参数字段还没拿到。顺序执行在这类链路里不需要额外配置什么排序组件。Jmeter 默认就让单个线程内的取样器按排列顺序执行你要做的只是把请求按业务顺序摆好然后处理参数传递。真正需要动脑筋的是数据依赖而不是顺序本身。2.2 单线程验证链路多线程压完整链路同样是先登录再下单再支付这套链路验证和压测的配置思路是不同的。只想验证链路通不通线程数设为 1 最省事。这样你看到的日志、断言结果、出错请求都对应同一条业务流排查问题非常清晰不会出现线程 A 和线程 B 的请求混在一起分不清的状况。想压测整条链路的性能线程数就要设成 N此时每个虚拟用户都会独立地从登录开始、走完整个链路。注意这个形态单个用户内部是串行的用户和用户之间是并发的。所以顺序执行和并发执行从来不是二选一的选择题而是可以组合的——线程内串行保证业务正确性线程间并行保证压力真实度。2.3 数据依赖怎么处理后置处理器加变量引用链路里最常见的依赖是上一步响应的字段要被下一步使用。这时候要用到后置处理器最常用的是 JSON ExtractorJSON 提取器。举个例子登录接口返回了一段 JSON里面有一个 access_token 字段。在登录请求上右键添加后置处理器 - JSON 提取器设置变量名 tokenJSONPath 表达式填 $.access_token缺省值随便填一个不可能出现的值用来暴露提取失败问题。然后在下一个下单请求的 HTTP Header Manager 里引用${token}。跑一次之后打开查看结果树确认请求头里的 Token 值已经动态替换链路数据就串起来了。并发跑这条链路时每个线程都有自己独立的变量副本不会互相覆盖这是 Jmeter 变量作用域的基本保证。只要你不是强行用 ${__setProperty} 之类的方式写到全局就不会出现线程之间串数据的问题。2.4 跨线程组的顺序setUp 和 tearDown 的正确用法有些前置工作和主压测任务有明确的先后依赖典型的就是测试数据准备和数据清理。压测开始前要先创建一批用户压测结束后要把这批用户删掉这就需要跨线程组的顺序控制。做法是把造数据的请求放在 setUp Thread Group 里把清数据的请求放在 tearDown Thread Group 里。执行顺序是setUp 组先跑全部结束后普通线程组开始普通线程组跑完之后tearDown 组才执行。这套机制非常适合构造数据和销毁数据的场景。另外一个相关但容易被忽略的细节如果普通线程组内的两个取样器之间需要固定间隔可以用固定定时器来控制。这和顺序执行不冲突只是给链条加上了节奏控制。3. 并发执行的重点从模拟多用户到模拟同时爆发3.1 最简单的并发把线程数填上去压一个查询接口的场景什么都不用加。建一个线程组里面放一个 HTTP 请求线程数设 100Ramp-up 设 5 秒循环次数设 1。执行后100 个虚拟用户会在 5 秒内陆续到达并发出请求稳态阶段接近 100 并发。这是 Jmeter 最原始的并发形态也是性能测试最基本的起步配置。这一步值钱的地方在于它模拟的是很多用户同时使用系统的常态压力。每个用户各自执行脚本没有额外的同步控制请求到达服务端的时间是自然分散的。绝大多数接口压测用这种方式就够用。3.2 集合点同步定时器制造瞬时冲击有些场景不满足于自然分散而是要模拟同一瞬间所有用户一起点击。典型的像秒杀、抢购、准点开抢这类瞬时冲击。这时候要加同步定时器Synchronizing Timer。同步定时器的位置很关键要放在需要并发的取样器前面。它有两个核心参数Number of Simultaneous Users to Group 表示要凑齐多少个线程才放行Timeout in milliseconds 表示超时时间。配置成 100 个线程、超时 1 秒的意思就是凑够 100 个线程就一起放过去如果 1 秒内始终没凑够先到的人也不再等待直接放行。加了同步定时器之后这 100 个线程会在同一时刻对目标接口发起请求服务端瞬间收到的请求量会明显高于自然并发形态。想看系统抗瞬时冲击能力这个方法最直接。3.3 一个线程内部的并行Parallel Controller还有一种并发容易被忽略同一个用户需要同时发出多个请求。比如打开一个页面浏览器会同时请求页面主文档、几张图片、几个 JS 和 CSS这些请求在真实客户端中是并发的。但 Jmeter 标准线程组里的取样器是串行的写成三个取样器就会有先后响应时间记录也不真实。JMeter 5.6 之后原生加入了并行相关能力可以在需要并发的采样器外面套一个 Parallel Controller它内部的取样器会在一个线程内并行发起请求。如果你还在用老版本要么升级要么借插件实现或者干脆用多个线程组模拟总之别指望普通线程组自己会并行。3.4 怎么判断并发是不是真的生效了压测跑完之后不要只盯着聚合报告看。判断并发有没有生效有几个直接的办法。最直观的是看查看结果树里的时间戳。如果同一个秒级时间窗口里出现了大量请求记录说明并发压力真实存在。也可以去服务端翻访问日志看一秒内到达的请求数是不是符合预期。更专业的做法是用 jpgc - Active Threads Over Time 这类监听器画出活跃线程曲线能看到线程数是否在预期时间内拉满、是否有提前掉线的情况。4. 实战对照同一种接口在不同执行模式下的表现差异4.1 实验场景设定为了把顺序执行和并发执行的区别讲得实在一点我拿一个简单的获取用户列表接口做对照。请求参数固定后端是一个普通的 Web 服务机器配置一般。下面说到的数字只是趋势示意不同的服务端能力数字会差很多重点看模式之间的差异逻辑。我跑了三种模式模式线程数Ramp-up额外配置A 单线程验证10无B 常规并发505 秒无C 瞬时冲击505 秒同步定时器凑满 50 人4.2 结果差异怎么解读模式 A 跑完后聚合报告里 TPS 很低平均响应时间也很低错误率为 0。这个模式本身就不是用来测性能的它的价值在于验证请求和断言是否正确。在模式 A 下出的所有问题都属于脚本问题而不是性能问题。模式 B 跑完TPS 会明显上升可能从单线程的每秒几十次涨到每秒两三百次平均响应时间会有小幅上涨错误率基本为零。这说明服务端能够并行处理请求压力开始真正作用到系统上。模式 C 的结果往往最有意思因为 50 个请求是同一瞬间打过去的服务端在同一时刻的排队压力远大于模式 B平均响应时间会更高错误率也可能出现。这不是说模式 C 配置错了而是它模拟的场景就是瞬时冲击系统能否扛住这一下才是测试目标。4.3 不同场景下的执行模式选型在实际项目里怎么选顺序执行和并发执行的组合我整理了一个自己常用的选型逻辑场景推荐配置原因接口链路功能验证线程数 1按顺序放取样器单线程保证链路数据干净问题好定位整条业务链路压测线程数 N链路请求按顺序放每用户串行走完整链路用户间并发单接口/多接口混合压测多个线程组同时跑一组一个接口模拟不同接口被同时调用瞬时高并发冲击多线程 同步定时器制造同一时刻的爆发压力模拟浏览器并发加载资源Parallel Controller单用户同时发多个请求这套选型逻辑基本覆盖了我遇到过的绝大多数压测场景。判断标准就一条你的测试目标是想看系统能不能扛住持续并发还是系统能不能扛住同一瞬间的集中冲击还是业务链路在多个用户同时操作时是否正确。4.4 项目里我建议的执行节奏顺序执行和并发执行在先后的配合上也有讲究。我一般遵循这样的节奏先在单线程里把接口链路全部调通断言调对数据依赖验证没问题然后开小并发验证脚本稳定性比如 10 个线程跑 2 分钟确认无误后再逐步放大到目标并发比如 50、100、200每档观察一段时间最后才进入正式压测用调度器控制持续时长。一上来直接 1000 并发是新手最容易犯的错。脚本本身的问题比如变量提取失败、断言写错、CSV 数据没配对在高压下会被无限放大刷出来的错误日志根本没法看。先小后大既是在压服务端也是在验证脚本。5. 绕开这些坑顺序与并发中最容易翻车的细节5.1 共用一份用户数据并发一上来全乱并发压测最常见的翻车点是用户数据没隔离。50 个线程共用一个登录账号拿到同一个 Token全都拿这个 Token 去下单服务端完全无法区分请求来自哪个用户数据全搅在一起断言也会随机失败。解决思路有两个一是用 CSV 数据集配置给每个线程分配不同的账号文件里每行一个用户线程启动后各自取自己的行二是让每个线程自己先登录一遍再执行业务把登录放到链路里而不是提前用登录后的状态。第二种做法多花一点请求量但更接近真实用户行为。如果你的 CSV 文件读出来是乱码先检查文件编码用 UTF-8 另存一遍通常就好。5.2 关键请求断言失败脚本却还在继续往下跑链路压测里有个典型情况登录请求因为参数或环境原因失败了但 Jmeter 不会因此停住后面的下单、支付请求照样发结果整条链路全是错误错误率直接爆表。如果你希望登录失败就停止这个线程后续的请求需要给它加流程控制。做法是在登录请求后面加断言再用一个 If 控制器判断${JMeterThread.last_sample_ok}是否为 false如果为 false 就执行一个 Test Action 采样器动作选 Stop目标是当前线程。这样关键步骤一旦失败线程会在该处停下来错误样本集中在真正失败的那个请求上排查成本低很多。这里要提醒一下Test Action 不是普通的 HTTP 请求它本身不会发网络请求只是用来控制执行流程的。右键菜单里添加采样器 - Test Action 就能找到。5.3 把循环次数当并发数用压了个寂寞前面提过一次但这个坑太常见了值得再说一遍。线程数 1、循环次数 1000跑出来的 TPS 再好看也不能证明系统能支撑 200 并发因为同一时刻永远只有一个用户在访问。还有一个变体有人把循环次数设成 10、线程数设成 20就以为自己是 200 并发。并发数只看稳态下的活跃线程数20 个线程无论循环多少次同时发起的请求上限就是 20。要检查自己是不是犯了这个错看一眼 Active Threads Over Time 曲线就明白了。5.4 只盯着平均响应时间被长尾数据带偏聚合报告里的 Average 这一列是最常被误读的。平均响应时间会被少数几个特别慢的请求拉高一旦出现长尾平均值根本无法体现系统的真实水平。正确的习惯是看 90th、95th 甚至 99th Percentile 这几列它们能告诉你绝大多数请求的响应时间分布在哪。另一个相关误解是把聚合报告里的 Samples 数量当成并发数。Samples 等于线程数乘以循环次数和并发数根本不是一回事。并发上了之后真正有价值的变化是吞吐量有没有跟着涨、错误率有没有跳变。如果并发从 50 提到 100TPS 纹丝不动错误率在涨说明系统瓶颈已经出现了RT 反而更像是结果而不是原因。5.5 排查乱序时先检查有没有特殊控制器如果某一天你的脚本执行顺序真的乱了别急着怀疑 Jmeter 线程模型。先检查线程组里有没有放特殊控制器随机控制器会随机挑选子节点执行交替控制器会切换执行Parallel Controller 会让子请求并行。这些控制器一旦出现它们作用域内的取样器执行顺序就不归默认模型管了。我自己排查过不少这类问题最后发现绝大多数都不是顺序和并发本身的问题而是控制器嵌套搞乱了执行结构。所以拿到一份执行顺序异常的脚本第一件事就是看线程组里挂的组件类型把特殊控制器的作用域缩小或移除再重新跑。在这个领域干得久了我最大的体会是顺序执行和并发执行从来不是互斥的两种选择而是一套组合拳线程组内的取样器串行是保证业务链路正确的底座线程间的并行是制造用户压力的来源同步定时器负责制造瞬时冲击Parallel Controller 用来模拟浏览器式的并发加载。把这四件事想透了Jmeter 的脚本执行逻辑基本就不会再让你困惑。