做接口测试的这些年,我见过太多团队把“并发测试”做成“重复调用”:Collection Runner一拖,迭代次数填个 20、50,勾上保存响应,点运行,看着那排绿色的 Total Passed 就宣布“并发没问题”。说句不好听的,这种玩法更多是在证明集合能按顺序跑 N 遍,而不是证明系统在同时收到多路请求时依旧稳得住。真正的并发测试要同时满足三件事:请求在同一时间窗口尽量集中地发出去,每个请求的数据互相独立、不串场,最终的结果按业务正确性来判定,而不是只看 HTTP 状态码。这三个条件,很多测试脚本连一个都没做到。
我并不是要劝退你用 Postman 做并发测试,恰恰相反,Postman 配合脚本和参数化,做小规模业务并发验证非常好用。但前提是你要绕过那 3 个最常见的坑:数据被循环复用、共享变量互相覆盖、以及把“请求成功”当成“业务成功”。这篇文章就围绕这 3 个坑展开,后面再讲一套我平时导出 Runner 结果做分析的方法,纯实操向,没有废话。
1. 先理解Postman并发测试的执行机制
很多人一上来就填参数,但根本没搞清楚 Postman 里“并发”到底是怎么跑起来的。这一段先把机制讲透,后面你踩坑时才知道往哪个方向排查。
1.1 Runner的串行迭代与并发执行模式
Postman 客户端里默认的 Collection Runner 执行方式是串行的:你选中的集合里有几个请求,它就先按顺序跑请求 A,再跑请求 B,一个迭代跑完再进入下一个迭代。这种模式说白了就是“把整个集合顺序重复 N 遍”,本质上跟在命令行里用脚本循环调接口差不多。
这种串行模式下,你就算把迭代次数填到 100,也只能证明这个接口能连续成功调用 100 次,完全模拟不了“100 个用户同时点下单按钮”的场景。真正的并发,需要在工具层面同时发起多个请求。目前常见做法是两条路:一条是用 Postman 新版本 Runner 里提供的并行执行配置,把并发数显式拉起来;另一条是用 Newman 命令行跑,通过--concurrency参数启动一定数量的并发执行实例。
以 Newman 为例,一条典型的并发执行命令长这样:
newman run api-test.postman_collection.json \ -d concurrency-test.csv \ --concurrency 10 \ --iteration-count 5这个命令的意图很直接:让 Newman 同时跑 10 个执行实例,每个实例手里最多有 5 轮迭代可用。当然,不同版本的命令行参数细节会有微调,你在实际用的时候以官方文档为准。我要强调的核心观点是:并发测试的本质是同一时刻的请求密度,不是请求总数。你填了 50 次迭代,如果工具是串行跑的,那就只是 50 次顺序请求;只有让多个执行实例真正同时发起请求,才叫并发。
理解了这个基础,你再回头看公司群里那些“并发测试通过”的截图,很多结论其实站不住脚。倒也不是说人家故意造假,很多时候是根本没弄明白工具背后的执行模型。
1.2 并发相关的三个基础参数:弄清楚再填
Postman 并发测试里有三个概念特别容易混淆:并发数、迭代次数、数据文件行数。我见过不少同学把这三个量填成一团乱麻,最后数据错位、结果失真,还找不出原因。
这三个参数的定位是这样:
| 参数 | 通常含义 | 建议 |
|---|---|---|
| 并发数 | 同一时刻同时执行的最大任务数量 | 从 5、10 开始,阶梯往上加 |
| 迭代次数 | 每个执行任务最多能跑的轮数 | 宁少勿多,先小批量验证 |
| 数据文件行数 | 可用的独立输入数据组数 | 必须大于等于并发数 × 单任务迭代数 |
用生活场景来类比:并发数相当于餐厅里同时开几个灶台,迭代次数相当于每个灶台最多能炒几道菜,数据文件行数相当于后厨备好的食材份数。如果只有 10 份食材,你却开了 10 个灶台、每个灶台要炒 5 道菜,那后厨就只能把同一份食材反复用,炒出来的东西当然会出问题。
在数据充足的前提下,并发数 × 迭代次数,可以理解为这次测试期望达到的总请求量级。但真正决定测试有没有效的,不是请求总量,而是数据行的独立性和请求发起的集中度。所以我给团队定的规矩是:运行之前先做一次“算术检查”,确认数据行足够,确认并发数没有超出本机连接数上限,确认迭代次数没有造成无谓的资源浪费。
2. 三个坑别踩:并发数据被复用、变量串台、假绿通过率
这个部分是全篇的重点。我把这些年在 Postman 并发测试里踩过最典型的 3 个坑,一个个拆开讲清楚:问题长什么样、为什么发生、正确姿势是什么。
2.1 坑一:迭代次数超出数据文件行数,请求数据被循环复用
这个坑可以说是并发测试里出现频率最高的。很多人准备数据文件时只准备了 10 条手机号,结果 Runner 里迭代次数填 50,Postman 会自动把数据文件从头再来一遍。你以为发出去了 50 个不同用户的请求,实际上 40 个请求都在重复使用第 1 到第 10 个用户的数据。
我举个实际发生过的例子:有一个并发领取优惠券的接口,测试准备了一个 CSV,里面是 10 个会员ID,脚本里通过pm.iterationData.get("memberId")取当前用户。运行 50 次并发后,前 10 次请求各领了一次券,后面 40 次请求又拿着同样的 10 个会员ID去领。这时系统里“每个会员限领一张”的规则触发,大量请求返回“已领取”的失败状态。最终报告看上去通过率惨不忍睹,但根本原因不是接口扛不住并发,而是测试数据自身就违反了业务规则。
这种问题在串行执行时往往暴露不出来,因为后一轮请求即使复用数据,你肉眼也能看出顺序;但并发一开,请求乱序交错,你很难一眼分辨哪些请求用了重复数据。
正确姿势就四条:
- 数据文件行数绝不小于并发数 × 迭代次数。如果数据量不够,优先减少迭代次数,拆分多轮去跑。
- 每条数据里放一个唯一业务字段。比如订单号、手机号、身份证号,便于断言时精确追踪到具体请求。
- 正式并发前,先跑一次单迭代,确认数据文件字段名与脚本引用完全一致。
- 动态数据尽量在脚本里生成。用
{{$guid}}、{{$timestamp}}、{{$randomInt}}这类动态变量拼业务流水号,避免完全依赖静态 CSV。
一句话总结:数据的“独立性”就是并发测试的生命线,数据一旦复用,结论直接作废。
2.2 坑二:并发回调中共享变量互相覆盖,测试结果串台
第二个坑比第一个更隐蔽,它不是肉眼能看出来的,而是脚本层面的变量冲突。串行执行时,集合变量、环境变量的读写顺序是确定的,问题不大;但到了并发环境,多路请求同时执行,脚本里的读写顺序完全不可控,共享变量很容易互相覆盖。
典型问题代码长这样:
// pre-request script 中写 pm.collectionVariables.set("currentUserId", pm.iterationData.get("userId"));这个脚本的逻辑是:每个请求开始前,把当前迭代的用户ID存成集合变量,方便后续请求去读。串行跑时一切正常,但并发一开就不行了——请求 A 刚把 userId=1001 写进集合变量,请求 B 立刻覆盖成 userId=1002,请求 A 后续断言一读就成了别人的数据。
我见过最离谱的例子是:并发创建订单后,测试脚本断言“订单号必须以当前用户开头”,结果因为共享变量被覆盖,明明接口返回正常,断言却随机失败,而且失败率毫无规律。团队排查了好几天,最后发现不是业务逻辑问题,是测试脚本自己在“内斗”。
正确做法也很明确:
- 并发测试脚本里,数据来源只读
pm.iterationData,不要频繁写入pm.environment或pm.collectionVariables这种共享容器。 - 每个请求要透传的唯一标识,放到请求头或请求体里,随请求本身走。比如用
X-Trace-Id传递流水号:const traceId = pm.iterationData.get("orderNo"); pm.request.headers.upsert({ key: "X-Trace-Id", value: traceId }); - 断言时优先验证响应体里返回的业务字段,与当前迭代数据做比对。例如:
pm.test("业务返回正确", function () { const resp = pm.response.json(); pm.expect(resp.code).eq(0); pm.expect(resp.data.bizNo).eq(pm.iterationData.get("orderNo")); }); - 如果确实需要跨请求缓存数据,建议把缓存作用域限制在请求内部或单次迭代内部,而不是整个集合共享。
这个坑的本质是:你在串行逻辑里养成了“全局变量随便用”的依赖,并发环境下这种依赖全都变成了隐患。写并发脚本时要养成一个条件反射:能局部就局部,能随请求带就别放全局。
2.3 坑三:HTTP 200 就算成功,忽略业务状态与数据一致性
第三个坑集中体现在结果解读上。不少测试脚本里的断言就写了一行“状态码为 200”,跑完看到绿油油一片,就认定并发没问题。但 HTTP 200 只能说明请求被服务端接收并正常响应了,压根不代表业务逻辑执行成功。
举个例子:一个余额扣减接口,10 个请求并发对同一账户做扣款。服务端可能返回了 10 个 HTTP 200,但其中 9 个接口响应体里写着“余额不足”或“重复扣款”,业务 code 是 40003。你只看状态码,报告全绿,实际上这个并发场景已经把账户余额扣出了问题。
更隐蔽的是数据一致性问题:接口返回成功,但数据库里某个状态字段没更新对,或者事务回滚了一半。这种问题 HTTP 层完全看不出来,必须通过业务字段校验、数据库后置检查才能发现。
所以我一直强调,并发测试里的“成功”必须是三层同时成立:
| 检查层级 | 检查内容 | 并发场景下的典型失败表现 |
|---|---|---|
| HTTP 层 | 状态码 2xx、响应时间、无连接异常 | 超时、5xx、连接被重置 |
| 业务层 | 响应体 code、message、关键业务字段 | 余额不足、重复领取、库存超卖 |
| 数据层 | 数据库记录、缓存状态、事务一致性 | 脏数据、少记录、状态不对齐 |
正确姿势是在 tests 里叠加业务断言。基础断言检查 HTTP 状态,还必须有更深入的业务校验:
pm.test("HTTP 状态正确", function () { pm.response.to.have.status(200); }); pm.test("业务状态正确", function () { const json = pm.response.json(); pm.expect(json.code).eq(0); pm.expect(json.data.status).eq("SUCCESS"); });在这个基础上,如果想验证数据一致性,就要在并发跑完后查数据库,确认结果是“多少请求成功就对应多少条有效记录”,而不是只看接口返回。并发测试要回答的问题,从来不是“请求打出去有没有回应”,而是“同时打这么多请求,业务还能不能按照规则正确执行”。
3. 结果分析技巧:学会给并发运行做体检
跑完并发只是第一步,更值钱的是结果分析。同样一批请求,有人只会看一个总通过率,有人能定位到具体是哪一秒、哪一批请求、哪个参数组合出了问题。差距从哪里来?从分析方法和指标选取里来。
3.1 导出Runner结果,重建请求时间线
Postman 的 Runner 界面跑完后会出一个结果页,很多人盯着页面看两眼就关了。正确做法是先点导出结果,把 JSON 文件存下来,再做二次分析。
导出结果里一般会包含迭代号、请求名称、开始时间、响应时间、HTTP 状态码、每一项pm.test的执行结果。字段名可能随版本略有变化,但核心信息都在。拿到这份 JSON 后,我通常会导入表格工具或用脚本筛选,按请求开始时间排序,重建出这次并发运行的真实时间线。
为什么要重建时间线?因为并发结果里,很多失败是“扎堆出现”的。比如某个时间窗口内 10 个请求同时打过来,连接池被打满,后面几个请求就可能报连接重置;又比如两个请求同时去更新同一条库存记录,数据库行锁冲突,后到的请求就会明显变慢。这些现象如果不按时间排序,你根本看不出来。
我习惯先把导出结果里“开始时间”字段按毫秒排序,再看相邻请求的耗时和失败情况。如果发现失败集中在某一秒,就要重点分析那一秒的请求量和服务端处理能力。这个步骤能帮你把“业务问题”和“异常流量问题”分清楚。
3.2 三看法定位并发失败:看分布、看耗时、看数据重复
多次实践下来,我总结了个“三看”分析法,适合大多数并发结果排查场景。
第一,看响应状态分布。把所有请求的响应码按 2xx、4xx、5xx、连接异常分组统计。如果 5xx 和连接异常占比高,说明服务端在并发压力下确实出现了稳定性问题;如果 4xx 占比高,往往不是系统扛不住,而是请求参数或业务约束被触发,这时要回查数据设计。
第二,看耗时分布。记录每个请求的响应时间,算平均值、最大值、P95 和 P99。不少场景下平均耗时很好看,但 P95 或者 P99 已经暴涨,这就说明多数请求确实很快,但有少量请求在某个环节严重排队。排队往往就是并发冲突的信号。比如 10 个并发请求,9 个耗时 100ms,1 个耗时 1.2s,那么那 1 个大概率是撞上了锁或者重试。
第三,看数据重复度。把失败请求对应的数据文件字段列出来,统计出现频次。如果失败集中在某个特定用户ID或订单号上,那大概率是该数据本身的业务状态与预期不符,比如这个用户领过券了、这篇文章已经点赞过了,而不是并发能力不行。这一步能避免你被一堆“造假失败”误导。
我办公桌上贴着一份分析清单,每次跑完并发都按这个顺序走一遍,效率高,也不容易漏问题。
3.3 并发结果的关键指标,记这几个就够了
很多人跑完并发喜欢截一大堆图表,但真正有用的指标就那几个。我不太推荐把性能分析那套“火焰图”“内存曲线”全搬进来,Postman 它不是专业性能工具,你应该关注它擅长给出的信息。
| 指标 | 口径 | 在并发测试中的作用 |
|---|---|---|
| 并发成功率 | 业务断言全通过的请求数 / 总请求数 | 核心结果,越低说明并发问题越严重 |
| 错误率 | 失败请求数 / 总请求数 | 用来拆解失败类型,区分业务失败和技术失败 |
| 响应时间分布 | 平均、最大、P90、P95、P99 | 发现排队、锁竞争、偶发慢请求 |
| 耗时走势 | 按请求开始时间分片统计平均耗时 | 观察随着并发推进,系统是否出现劣化 |
| 失败集中度 | 失败请求是否集中在特定数据/特定时间窗口 | 区分数据问题与系统问题 |
举一份我实际跑出来的结果片段作参考。假设并发 10、迭代 5,导出后按开始时间排序:
| 迭代号 | 开始时间 | 响应耗时 ms | HTTP 状态 | 业务 code | 判定 |
|---|---|---|---|---|---|
| 1 | 15:02:03.450 | 105 | 200 | 0 | 成功 |
| 2 | 15:02:03.451 | 98 | 200 | 0 | 成功 |
| 3 | 15:02:03.461 | 920 | 200 | 1003 | 失败-余额不足 |
| 4 | 15:02:03.462 | 450 | 200 | 1003 | 失败-余额不足 |
| 5 | 15:02:03.478 | 110 | 200 | 0 | 成功 |
一眼就能看出两件事:第一,失败不是均匀分布,而是集中在某个时间窗内;第二,失败请求耗时明显偏高,说明大概率是在数据库层面排队或撞了行锁。顺着这个线索去查对应时间的服务端日志和数据库锁等待,基本就能定位到根因。
4. 常见坑的补充排查与我对Postman并发的边界认识
前面三个坑是并发测试里的“主线剧情”,但在实际执行时,还经常会碰到一些杂七杂八的运行问题。这里我整理一个排查速查表,再聊几句 Postman 并发测试的适用边界。把这些搞清楚,你才算真正掌握了正确姿势。
4.1 常见执行故障排查速查表
我自己在项目里经常遇到下面的现象,对应的排查方向也一并列出来:
| 故障现象 | 常见原因 | 排查思路 |
|---|---|---|
| 部分请求响应超时 | 并发数过高、接口本身处理慢、本机带宽受限 | 降低并发数观察是否缓解;看服务端日志耗时 |
| 连接被重置 | 本机连接数打满、服务端主动断开、网络不稳定 | 检查并发数是否超过本地端口上限,减少并发重试 |
| CSV 中文乱码 | 文件编码不是 UTF-8 | 用编辑工具另存为 UTF-8 编码,再重新导入 |
| 断言随机失败 | 共享变量被覆盖、数据被复用 | 检查脚本是否在并发回调里写了集合变量/环境变量 |
| 数据文件字段取不到值 | CSV 字段名与脚本引用不一致 | 单迭代跑一次,打印pm.iterationData内容核对 |
| 运行时间比预期长很多 | 集合里存在等待逻辑、超时设置过大、保存了大量响应体 | 检查每个请求的超时配置,关闭不必要的响应保存 |
这些故障很多不是一起出现的,但它们的排查思路是共通的:先缩小范围,用最小并发复现,再逐层判断是脚本问题、数据问题还是服务端问题。不要一上来就怀疑接口性能,先把自己的脚本和数据环境检查一遍,能省下大量时间。
4.2 Postman并发测试适合什么场景,不适合什么场景
必须把话说透:Postman 做并发测试有它的适用边界。它特别适合中小规模的业务并发验证,比如验证“并发领取优惠券不会超发”“并发提交订单不会重复入单”“并发修改同一资源时锁是否正确”。这种场景下,请求量一般在几十到几百,跑一次只需要几分钟,Postman 的灵活性和脚本能力完全够用。
但它不适合做大规模压测、长时间稳定性测试、精细性能指标采集。Postman 跑在单机上,本身受到操作系统连接数、内存、CPU 的限制,你拿它去模拟上万个并发用户,结果既不准确也没有参考价值。那类任务应该交给专门的性能测试工具,或者公司内部的压测平台,它们对线程模型、采样统计、分布式施压的支持要专业得多。
所以我的建议是:Postman 负责业务功能层级的并发验证,把接口的业务规则、数据隔离、幂等性这些逻辑先跑顺;真到容量评估阶段,再把同样的业务脚本迁移到专业工具上去放大压力。两个工具各有分工,别指望一个工具解决所有问题。
4.3 三个能长期受益的执行习惯
最后分享三个我在实际操作里总结出来的习惯,都不复杂,但长期坚持下来收益很明显。
第一,先单后并。任何集合改动之后,先跑一次单迭代,确认请求本身没问题;再跑 2 到 5 个低并发,确认脚本在并发下不会串数据;最后才放大并发数。这样能最大限度把测试脚本自身的问题隔离在正式跑并发之前。
第二,数据可追踪。每次并发跑之前,给这轮测试定义一个批次号,通过请求头发进去;每条测试数据尽量带上唯一业务ID。跑完出问题,你拿着请求日志里的批次号和业务ID一查,上下游调用链全都能串起来。没有可追踪标识的并发测试,出了问题基本只能靠猜。
第三,并发场景也要版本管理。接口定义、测试脚本、数据文件、导出结果,都应该随版本保存。很多并发问题是在接口变更后才暴露出来的,你今天发现“并发没问题”的脚本,下个月接口改了个参数名,可能就不能用了。把并发场景纳入日常回归,比临时抱佛脚可靠得多。
这三个习惯没什么高深技术含量,但能让你从“用 Postman 跑并发”进化成“把 Postman 的并发测试结果当作可信依据的人”。测试结论到底可不可信,往往就取决于这些看似不起眼的细节。