写在前面

目前我在一家 ToB 公司负责测试管理工作,团队以中级测试工程师为主,绝大多数成员尚未沉淀或梳理过体系化的测试方法。在我刚进入团队后的性能测试方案评审中,我发现大家其实并不缺少性能执行能力,JMeter/Python 脚本都能写,但一涉及性能测试中的核心概念,沟通就会模糊,动作就会变形,例如:

这种模糊和变形导致的问题是:

这些问题并非孤例。第一,某些概念本身确实容易被混淆,加上团队成员无论在研发深度还是测试工具深度上都理解不深刻,因此很容易按照自己的理解去执行;另一方面,不同项目之间缺少统一的口径对齐,也始终没有一个明确的角色来牵头讲清楚相关术语。

基于这一现状,我梳理了测试团队中容易被研发/客户挑战、容易踩坑的几个关键概念,写下了这篇文章。文章目的不是从零开始讲授 “怎么做性能测试” 或者 “某个测试工具怎么用”,而是希望能把那些说不清、容易错的概念尽可能讲清楚。同时也希望这篇文章在团队内部能成为一本 “翻书式” 参考文档,让团队成员在讨论性能问题时,能站在同一套概念体系下对话。


明确性能测试目标

对于常规项目而言,性能测试通常围绕三个核心目标展开:定值压测、探底压测、长时压测

定值压测

定值压测是指在固定负载条件下,对系统的响应时间和处理能力进行定量测试。这里的 “固定负载” 通常体现为预设一个固定的压力。通过这种方式,可以判断系统在预期业务压力下,是否能够满足合同或 SLA 中约定的性能指标。一般定制压测可以分为脉冲压测(定值且持续时间短)和非脉冲压测(定值且持续时间长)。其中非脉冲压测时间一般在 10-60 分钟,脉冲压测一般在秒级或者 5min 以内。

非脉冲压测

脉冲压测

探底压测

与定值压测关注 “既定负载下的表现” 不同,探底的核心目标是找出系统能够承受的最大压力极限。测试通常从低压力开始,逐步增加负载,直至系统性能不再线性提升、甚至出现明显下降的拐点。该拐点即为系统瓶颈所在,可帮助定位限制整体吞吐量的关键组件,为后续优化提供方向。探底压测中,每个负载阶梯 一般压测 10-20 分钟。

长时压测

长时压测旨在模拟真实生产环境中的长时间持续负载场景,用于检验系统在长时间运行下是否存在内存泄漏、资源回收异常、连接池耗尽等慢性问题。通常建议将压测时长维持在 6~12 小时,期间保持稳定的业务压力,并持续监测 CPU 利用率、内存占用量、GC 频次等关键指标的变化趋势。

一般性建议:

对于迁移类或重构类项目,用于对比改造前后的性能差异,一般采用定值压测

如果新项目已有明确的性能目标,可采用定值压测/探底压测。使用定值压测执行速度快,但不容易辅助研发定位拐点。使用探底压测执行速度慢(需要一个阶梯一个阶梯去压测),但容易辅助研发定位拐点。具体采用哪种,结合项目紧急程度和研发诉求决定。

如果新项目未明确性能目标,一般采用探底压测,且最终测试结论中不给测试是否通过,只给出事实数据。

对于所有项目,一般都会进行长时压测。但通常优先级低于定值压测/探底压测,可根据项目周期和风险判断动态取舍。


明确系统任务类型

被测系统的任务类型可归纳为两大类:同步类接口异步类任务

区分同步与异步的核心意义在于:不少测试工程师容易将同步类接口的压测模式直接套用在异步类任务上,导致压测产生的负载与实际场景严重偏离。

以某异步数据处理任务为例:需求中明确“并发任务数为 10,任务平均执行耗时不超过 10 分钟"。部分测试人员沿用同步类接口的压测思路,以每秒触发 10 个任务的速率连续施压 5 分钟,系统因短时间内接收到大量任务触发而处理不过来,最终被测试人员判定 “压测不通过”。

然而,该项目语境下的 “并发任务数为 10” 指的是数据处理流水线中同时处于处理状态的任务峰值为 10 个而不是异步任务的启动接口并发为 10。如果按上述同步方式压测,实际涌入流水线的任务总量为 10 × 5 × 60 = 3000 个,远超系统设计容量。正确的做法应该是:第 1 秒内通过异步任务启动接口一次性触发 10 个任务后,便不再持续发压,观察系统能否在 10 分钟内完成这批任务。10 分钟后再通过异步任务启动接口启动 10 个任务,确保流水线中并发处理的任务数始终维持在 10 以内。

一般来说,异步类任务和同步类任务相比,在压测实施方式上有一定区别:

并发控制:一般异步压测通常只做瞬时并发就可以满足要求,目标是在某一时刻 “调起” 指定数量的后台任务,然后让其在后台运行即可,而不是拿着一个任务启动接口一直持续施压。

指标采集:由压测工具返回的异步任务的响应时间成功率,仅代表 “任务提交” 这个接口的成功与否,并非任务实际执行的耗时与成功率。真实的任务处理指标需通过界面查询、日志分析、数据库字段等方式获取。


明确性能测试模型

性能测试方案的设计,需要从四个维度构建测试模型:流量模型、业务模型、数据量模型、缓存模型。四者关系如下图所示:

明确流量模型

在客户的原始需求文档中,经常见到以 “在线用户数”、“并发用户数” 等作为性能指标,但测试人员在撰写测试报告的时候,却以工具的线程数或 QPS 数作为单位。因此在实际项目中,我经常会问,在线用户数、并发用户数、QPS、RPS、TPS、线程数,它们究竟有何区别?若文档要求 “并发用户数为 10”,流量模型应如何设计?

上图上半部分为用户与系统的真实交互,下半部分为压测工具对真实场景的模拟。核心概念如下:

举例说明

在上图上半部分的真实场景中,有 3 个在线用户,同时在某个时刻下有 2 个并发用户:用户 A 在 1 秒内完成 2 个请求(构成 1 个事务),用户 B 在 1 秒内完成 1 个请求(只完成了一半事务)。此时系统并发用户数 = 2QPS = 3TPS = 1.5

在上图下半部分的压测模拟中,工具启动 2 个线程,假定线程没有设定睡眠时间且线程为 BIO(阻塞式 IO)模式,这就意味着在每个线程中一个请求执行完成后会继续执行下一个请求。如果每个线程 1 秒内发送 2 个请求,则线程数 = 2QPS = 4

一般而言

ToC 系统:通常流量较大、实时性要求高、采用微服务架构,更适宜使用 QPS/RPS 作为性能指标。该指标既贴近用户请求的真实形态,也能直观反映系统承受的压力。

ToB 系统:因业务操作相对复杂,一般以 并发用户数 或 TPS 作为衡量基准。其中并发用户数是绝大多数客户熟悉且易于理解的口径,TPS 仅少数具备一定技术背景的客户会主动提出。

客户习惯偏差处理:部分 ToB 客户倾向于直接用 在线用户数 来评估性能。此时,测试团队需主动和项目经理沟通,要求项目经理向客户澄清 “在线用户数” 与 “并发用户数” 的本质区别,并引导客户将需求转化为明确的并发用户数或 TPS 指标,以确保测试目标与系统实际承载能力对齐。


明确业务模型

业务模型一般是指在一批流量中,各个业务流量的配比。在明确了流量模型之后,为什么还必须明确业务模型?下图可以直观说明原因:

假设压测目标为 QPS = 100,被测对象是一个机器人对话接口。不同的 query 语料会命中不同的算法模型,而不同模型的资源消耗差异巨大:

结论相同的 QPS,不同的业务配比,对系统造成的压力截然不同。

那么,如何确定业务模型?

对于已上线的项目:直接参考线上日志的实际流量分布。建议提取近 7 天的日志进行分析,流量配比按业务接口、意图类型、请求参数等维度统计。日志规范的前提下,无需编写复杂脚本,一般 Linux Shell 即可快速处理(如下图示例:过滤接口→提取业务类型字段→统计排序)。

对于未上线的新项目:依据对业务的理解给出初始配比,并与客户/项目经理/产品经理对齐确认。若对方无异议,即以此作为压测依据。

若经评估,该业务接口的性能表现与请求配比无关,也可跳过此步骤。


明确数据量模型

对于大多数依赖数据库查询的系统,其性能表现与数据规模高度相关。因此,性能压测前需明确数据量模型,确保压测环境具备代表性。


明确缓存模型

当系统依赖缓存时,若反复使用相同的压测语料,会导致持续命中缓存,从而低估实际服务端的处理开销。理想情况下,应根据既定的缓存命中率来设计语料。

需要注意的是:


明确性能准出标准

吞吐率

系统完成任务的实际速率应与流量模型的预期一致。

响应时间

响应时间度量口径

错误率

资源利用率

长时压测需额外关注以下趋势


⚠️ 特殊场景警示——放水排水模型

存在这样一种典型误区:压测过程中错误率为 0、平均响应时间达标,但系统实际并不具备对应 QPS 档位的承载能力。

如下图所示,假设系统吞吐能力为 5 QPS,任务队列容量为 50,压测输入为 10 QPS,持续 3 秒。

在前 3 秒内,队列尚未填满,响应时间无明显上升,错误率为 0。若此时停止压测,极易误判为 “测试通过”。但若将压测时长延长至 10 秒,队列溢出后错误率将急剧上升,系统瓶颈随之暴露。

问题本质:系统具备一定的 “蓄水” 缓冲能力。若压测时长不足,压力仍在缓冲容量范围内,问题不会显现;但一旦压测时长足够长,蓄水池终将填满,性能缺陷便会暴露。

结论:对于具备排队或缓冲机制的系统,仅靠短时压测无法有效评估其真实承载能力,必须通过足够时长的持续压测来验证系统的性能。


在 Jmeter 中控制流量模型和业务模型的方法

如何控制流量模型中的 QPS

在 JMeter 中,发压通过线程实现,但线程数 ≠ QPS。JMeter 线程采用 BIO 模型,每个线程需等待上一个请求返回后才能发送下一个请求。因此,线程数、QPS、平均响应时间之间存在如下估算关系:

QPS = 线程数 × 1000 (ms) / 平均响应时间 (ms)

JMeter 中控制 QPS 的三种方法

方法一:通过手工调整 Constant Throughput Timer,进一步控制 QPS(相当于汽车手动挡)

  1. 先用 1 个线程压测 10 秒,获得接口的平均响应时间。

  2. 根据目标 QPS 估算所需线程数:线程数 ≈ QPS × 平均响应时间(ms) / 1000,并在 Thread Group 中配置。

  3. 添加 Constant Throughput Timer 严格限制 QPS 上限(不限制下限)。

* 注意:Target throughput 单位为 QPM(每分钟请求数),需将目标 QPS × 60。

* Calculate Throughput based on 选择 All active threads

方法二:仅通过 Thread Group 线程数控制(相当于另一种手动挡)

若对系统性能有较准确的预判,也可不添加任何定时器,直接通过调节线程数控制 QPS。此方式要求测试者对 “线程数 → QPS” 的换算关系有足够把握。

方法三:Ultimate Thread Group + Throughput Shaping Timer(自动档,需安装插件)

  1. 在 Throughput Shaping Timer 中设定预期的 QPS 曲线,并将该元件命名为 timer

  2. 在 Ultimate Thread Group 中,通过 ${\__tstFeedback(timer,1,500,30)} 函数动态调整线程数,实现 QPS 的自动跟随。


如何控制业务模型配比

方法一:Random Variable + If Controller

  1. 使用 Random Variable 生成 1~100 的均匀分布随机数(如变量名 prob)。

  2. 添加三个 If Controller,分别设定条件,实现 60%、30%、10% 的概率分流:

* ${\__jexl3(${prob}>=1 && ${prob}<=60,)}

* ${\__jexl3(${prob}>=61 && ${prob}<=90,)}

* ${\__jexl3(${prob}>=91 && ${prob}<=100,)}

方法二:CSV 文件控制

同样以 60%、30%、10% 为例,可准备 100 条语料的 CSV 文件,其中 60 条对应场景一,30 条对应场景二,10 条对应场景三。通过 CSV Data Set Config 循环读取,天然实现配比控制。


执行性能测试过程中的注意事项

压测执行期间,务必注意以下事项:

  1. 通知研发人员:压测前与开发团队同步,便于配合排查问题。

  2. 监控双方资源:既关注被测机(CPU、内存、网络、磁盘),也关注施压机。若施压机自身资源饱和,瓶颈可能出现在压测工具端。

  3. 环境确认严禁非预期的压到线上生产环境务必多次核对 IP、域名、测试标识。避免由于测试本身失误导致的线上事故。

  4. 避峰执行:尽量不与其它系统联调、回归测试等任务并行,避免相互干扰。


以上即为我团队内对性能测试核心关注点的梳理,也在很大程度上决定了本次性能测试是否成功。


↙↙↙阅读原文可查看相关链接,并与作者交流