性能测试:性能测试工程师到底在测什么

一提到性能测试,第一反应就是:

  • 并发打多大
  • QPS 跑多少
  • 平均响应是不是低于 1 秒
  • 工具用 JMeter 还是别的

这些问题当然重要,但如果性能测试只停留在这一层,它最后通常只会变成一场“把流量打上去然后看几张图”的活动。

真正有价值的性能测试,应该回答的是一组更接近系统决策的问题:

  • 系统在什么负载区间内是健康的
  • 从哪里开始退化,退化是平滑还是断崖
  • 哪一层最先限制系统继续增长
  • 这个限制会不会扩散成更大的系统性风险
  • 当前架构的哪些默认假设已经开始站不住
  • 如果业务量继续增长,下一步最该补的能力是什么

所以“性能测试工程师到底在测什么”这个问题,本质上不是在问测试工具,也不是在问指标名词,而是在问:

性能测试这件事,到底在为团队识别什么风险、提供什么判断、支撑什么决策。

一、性能测试测的不是“压”,而是系统在负载下的行为变化

性能测试经常被直接等同于“压测”。
这个理解不能说错,但太窄了。

因为“压”只是手段,真正重要的是:

系统在不同负载强度、不同持续时间、不同业务结构下,会表现出什么行为。

这里面至少有三层含义。

1. 不是只看能不能扛住

系统不是只有“正常”和“挂掉”两种状态。
真实世界里,更常见的是一条退化曲线:

  • 一开始完全健康
  • 然后尾延迟慢慢变差
  • 再接着错误率开始抬头
  • 再往后吞吐不再增长
  • 最后进入明显不稳定区

如果测试只看“最后挂没挂”,那很多真正有价值的信息都会被错过。

2. 不是只看单点接口

很多性能问题不是单个接口本身慢,而是系统链路在负载下开始相互拖拽。

例如:

  • 一个查询接口慢,拖住应用线程
  • 线程池堆积,连带其他接口也慢
  • 缓存 miss 放大数据库压力
  • 下游依赖抖动,让上游重试流量继续放大

这说明性能测试往往不是在测某个接口的快慢,而是在测整个系统如何在压力下相互影响。

3. 不是只测峰值,还要测持续性

有些系统瞬时看起来非常能扛,但一旦持续 30 分钟、1 小时、2 小时以后,问题才开始出现:

  • 内存缓慢上涨
  • 连接不释放
  • GC 变差
  • 磁盘写入开始堵

所以性能测试测的也不是“瞬时爆发能力”这么简单,而是系统在持续负载下是否还能稳定工作。

二、从本质上说,性能测试测的是“资源竞争”和“退化传播”

如果把性能问题再抽象一点,大多数问题最终都绕不开两件事:

  • 资源竞争
  • 退化传播

1. 资源竞争

系统在低流量时,很多资源都显得“够用”:

  • CPU
  • 内存
  • 数据库连接
  • Redis 连接
  • 线程池
  • 网络带宽
  • 磁盘 I/O

但一旦业务量上来,资源之间开始激烈竞争,系统原本隐藏的边界就会被快速暴露。

2. 退化传播

更麻烦的是,性能问题很少只停在一个点上。

例如:

  • 数据库变慢
  • 应用线程被拖住
  • 请求开始堆积
  • 网关超时上升
  • 重试又把压力加回系统

这时候问题已经不是“数据库慢”,而是开始向整条链路扩散。
性能测试的价值,就在于识别这种扩散是怎么发生的。

三、性能测试工程师真正要回答的,不是一个数字,而是一组边界

最常见的一句问题就是:

“这个系统最多支持多少并发?”

这个问题表面上很合理,但如果最后只给出一个数字,通常价值并不高。

因为系统能力不是单点值,而是一组条件下的能力边界。
它至少会受到这些因素影响:

  • 请求类型
  • 数据规模
  • 数据冷热
  • 读写比例
  • 持续时间
  • 缓存命中率
  • 下游依赖状态

所以更有价值的性能结论,通常不是:

  • 最大支持 800 并发

而是更像:

  • 在 400 并发以内系统处于健康区
  • 500 并发开始尾延迟明显恶化
  • 650 并发后数据库连接池等待上升,系统进入风险区
  • 800 并发只是极限冲高,不应作为安全容量

这种边界式结论才真正有决策意义,因为它能告诉团队:

  • 安全工作区在哪里
  • 风险从哪里开始
  • 极限区大概在哪

四、性能测试测的不只是“快不快”,更重要的是“稳不稳”

过于关注平均响应时间,这是很典型的问题。

因为真实用户感知到的,很多时候不是平均值,而是:

  • 抖不抖
  • 卡不卡
  • 偶发请求是不是特别慢

一个系统即使平均值很好看,也可能在真实体验上很差。
例如:

  • Avg 200ms
  • P99 5s

这类系统看报表好像挺漂亮,但线上用户一定会感受到明显问题。

所以我一直认为,性能测试工程师测的一个关键对象,就是系统的“稳定性质量”:

  • 尾延迟稳定不稳定
  • 同样压力下重复执行是否一致
  • 长稳压下曲线是否持续恶化

换句话说,性能测试不只是测速度,还在测系统是否可靠。

五、性能测试其实也在测“架构假设”是不是还成立

这一点特别重要,也特别容易被忽略。

很多系统上线时,天然带着一堆没有写出来的默认假设,比如:

  • 缓存命中率会比较高
  • 某类接口占比不会太大
  • 数据量不会突然暴涨
  • 某个第三方依赖应该足够稳定

这些假设在平时可能没问题,但业务一变化,它们就可能集体失效。

性能测试一个很高价值的作用,就是去验证这些假设到底还能不能站住。

例如:

  • 如果缓存 miss 明显变多,数据库会不会被直接打穿
  • 如果促销活动导致写请求暴增,锁冲突会不会快速放大
  • 如果查询条件更复杂,搜索链路会不会提前进入尾延迟恶化区

这意味着性能测试不仅是在测当前系统快不快,也是在测:

  • 当前架构是不是还适合继续承载业务增长

六、不同类型的性能测试,其实在回答不同问题

把所有性能测试都混在一起叫“压测”,这会导致目标非常模糊。

更倾向把性能测试至少分成下面几类。

1. 容量类

关注:

  • 当前资源下最多能支撑多大业务量
  • 健康区、风险区、极限区分别在哪里

七、如果要从零开始做一次性能摸底,更合适的落地方式如下

只讲“性能测试在测什么”还是偏抽象。
真到项目里,通常会先把一次最小可执行摸底跑起来,再决定后面要不要做更重的压测。

一个比较实用的落地顺序通常是:

  1. 先选一条核心链路
  2. 给出一个业务目标值
  3. 准备一套最小监控面
  4. 做一轮分阶段升压
  5. 对齐退化拐点和资源证据
  6. 输出健康区、风险区和后续动作

例如一个典型的接口链路摸底,先定成这样:

项目 实践口径
目标链路 搜索接口 + 详情接口
核心目标 活动高峰 1.2 倍时仍可用
执行方式 100 -> 200 -> 300 -> 400 并发逐段升压
每段时长 10 分钟预热 + 20 分钟正式观察
必看指标 TPS、P95、P99、错误率、CPU、数据库连接池等待
停机线 错误率持续 3 分钟超过 1%,或数据库连接池耗尽

这里最关键的不是“并发值写多少”,而是每一段都要能回答一个明确问题:

  • 这一段系统是不是还在健康工作区
  • 哪个指标先开始失真
  • 失真是偶发噪音,还是开始形成趋势

八、一次性能摸底里我最少会准备哪些材料

如果连最基本的材料都没准备齐,性能测试很容易变成“流量打上去了,证据没留住”。

通常至少准备下面这些内容:

1. 一张链路图

哪怕很简化也要有,至少画出:

  • 流量入口
  • 应用服务
  • 数据库
  • Redis
  • MQ
  • 第三方依赖

因为后面看到瓶颈时,你需要快速知道它是在主链路、旁路还是依赖层。

2. 一张压测记录表

现场通常会维护一张很朴素的表:

阶段 并发 TPS P95 P99 错误率 现象 初步判断
stage-1 100 620 180ms 320ms 0 稳定 健康区
stage-2 200 1180 240ms 520ms 0 稳定 健康区
stage-3 300 1540 410ms 1.1s 0.2% 查询偶发超时 接近风险区
stage-4 400 1600 920ms 2.8s 1.4% 数据库连接池等待上升 风险区

这张表的价值很高,因为它把“执行过程”直接沉淀成后续报告的骨架。

3. 一组固定观察窗口

现场通常会明确谁负责看什么:

  • 压测侧看吞吐、延迟、错误和脚本异常
  • 应用侧看线程池、GC、接口日志
  • 数据库侧看连接池、慢 SQL、磁盘等待
  • 中间件侧看 Redis、MQ、网关状态

这样现场不容易所有人一起盯同一张 TPS 图。

九、更看重的一套最小排查动作

第一次做性能测试,一出问题就开始“全员找原因”。
这种方式通常很乱。

更常用的最小排查动作是:

  1. 先确认压测机是否健康
  2. 再确认错误是不是业务错误还是工具错误
  3. 对齐吞吐、P99、错误率开始变差的准确时间
  4. 回看同一时间窗口的应用、数据库和中间件图
  5. 只抓最早出现异常的那个点先解释

这里有一个很重要的实践原则:

一次性能排查里,先解释“第一个异常”,不要一上来解释“最后系统为什么慢”。

因为最后的慢,很多时候只是前面某个瓶颈扩散后的结果。

2. 稳定性类

关注:

  • 长时间运行会不会退化
  • 是否有内存泄漏、连接泄漏、缓存抖动、文件句柄耗尽

3. 瓶颈定位类

关注:

  • 当前系统最先卡在哪
  • 哪一层最先开始限制系统增长

4. 方案验证类

关注:

  • 做完架构调整之后收益到底多大
  • 继续扩节点是否还有价值

5. 风险评估类

关注:

  • 上线、大促、迁移前最大的风险在哪里
  • 生产流量上来以后最可能先炸哪一层

如果这些测试目标不区分,最后最容易发生的事就是:

  • 工具跑了
  • 数据也有了
  • 但没人知道这次测试到底是为了回答什么问题

七、在项目里最常见的几个性能测试误区

误区 1:把工具吞吐当成系统吞吐

比如 JMeter 打不上去,有些人第一反应就是:

  • 系统扛不住

但真实原因可能是:

  • 压测机 CPU 已经满了
  • 本地端口耗尽
  • 脚本参数化有问题
  • 连接复用没配好

性能测试工程师首先要确认的,不是系统有没有问题,而是“施压本身是不是可信”。

误区 2:只看平均响应时间

平均值太容易掩盖真正风险。
很多严重问题都藏在:

  • P95
  • P99
  • 错误率抬头之前的尾部恶化

误区 3:只看接口,不看资源和链路

接口慢只是表象。
如果不看:

  • CPU
  • 线程池
  • 数据库连接
  • Redis
  • 磁盘
  • 网络

那大多数结论都只能停留在“变慢了”,无法进入“为什么慢”。

误区 4:用不真实的流量模型,得出很真实的结论

例如:

  • 所有请求都用同一组参数
  • 没有冷热数据差异
  • 没有读写比例变化
  • 没有真实业务链路组合

这种测试即使结果很漂亮,也不一定有实际价值。

误区 5:压测完只给数字,不给解释

例如只说:

  • 支撑 1000 并发
  • 错误率 2%

但不说:

  • 为什么从这个点开始退化
  • 哪一层是主要瓶颈
  • 下一步最该怎么优化

这种结果对团队的真实帮助很有限。

八、性能测试工程师真正重要的能力,不只是会用工具

性能测试能力经常被等同于:

  • 会 JMeter
  • 会看 TPS
  • 会出报告

这只是基础,不是核心。

更关键的是真正重要的能力至少包括下面几类。

1. 场景抽象能力

能把真实业务翻译成:

  • 流量结构
  • 并发模型
  • 数据模型

2. 指标理解能力

能解释:

  • 吞吐、延迟、错误率、资源之间的关系

3. 瓶颈归因能力

能从表象一路追到:

  • 应用
  • 中间件
  • 数据库
  • 基础设施

4. 风险翻译能力

能把测试结果翻译成团队听得懂的决策语言:

  • 能不能上线
  • 要不要扩容
  • 最先该动哪一层

九、更常用的分析顺序

如果一次性能测试结果出来,通常不会马上先看某一层监控,而是按下面顺序走。

1. 先确认施压是否可信

确认:

  • 压测模型是否接近真实
  • 压测机是否先成瓶颈
  • 脚本是否有明显失真

2. 再看系统外部表现

确认:

  • 吞吐
  • P95 / P99
  • 错误率

3. 再看资源与依赖

确认:

  • CPU
  • 内存
  • 数据库
  • Redis
  • 磁盘
  • 网络

4. 最后再做因果判断

也就是回答:

  • 谁最先开始限制系统继续增长
  • 问题如何向外扩散

结语

性能测试工程师真正测的,不是“并发打多大”,也不是“某个工具会不会用”,而是系统在负载下的真实行为、退化方式、风险边界和架构假设。

更准确地说,一次真正有价值的性能测试,至少要回答清楚下面几件事:

  • 系统在什么区间是健康的
  • 从哪里开始退化
  • 谁最先限制系统继续增长
  • 当前架构的哪些假设开始站不住
  • 下一步优化最该投到哪里

如果这些问题回答不出来,性能测试就很容易退化成一次“把流量打上去然后截图”的动作;
如果这些问题能回答清楚,它就会真正成为容量规划、架构优化和上线决策的重要依据。