前几天有同事问我:“性能测试是不是就拿工具压一压,看看报不报错?”我说你要是这么想,后面一定得踩坑。我最早做性能测试时也是这个认知,后来在一次活动大促里,系统在流量翻倍的情况下被打垮,技术负责人当场问“你们之前不是测过吗”,我才发现自己压根没回答真正的问题。
这篇是“性能测试实战全流程”系列的第一篇,重点讲一件最容易被忽略的事:为什么做性能测试。它到底能解决什么问题、怎么判断投入产出、目标怎么定、指标怎么选、有哪些常见的坑,以及性能测试怎么在一个团队里从“一次性活动”变成“常态化能力”。适合刚接触性能测试的QA、后端开发、运维,也想推荐给那些想推动性能测试、但不知道从哪开始的技术负责人。
1. 先讲一次事故:我以为的功能正常,被流量揭穿了
1.1 活动当天发生了什么
很多年前,我给一个积分商城做支持工作。功能测试全过,联调也完成了,预发环境一切正常。活动上线二十分钟后,首页接口长时间无响应,用户点一下按钮就转圈,后台CPU告警,网关开始重试,数据库连接池被打满。最后只能紧急下线活动入口,回滚版本。
事后复盘,原因让人脸红:
- 订单查询语句缺了一个联合索引,平时几十QPS看不出来,活动峰值上千QPS后,慢查询直接把数据库拖垮;
- 应用代码里有一段双重循环做对象匹配,数据量小的时候几百毫秒,数据量一大直接吃满CPU;
- 服务间调用的超时时间设得太短,上游一慢,下游立刻报错,错误率像滚雪球一样放大。
这些在功能测试阶段完全不出现。功能测试验证的是“对不对”,性能测试验证的是“快不快、稳不稳、扛不扛得住”。那次事故之后,我彻底改了做测试的思路:任何有并发、有流量预期的系统,都不能只靠功能测试收尾。
1.2 性能测试到底在问系统哪三件事
性能测试说复杂也复杂,说简单也简单,本质上是在问系统三个问题:
- 多快:用户发起一个请求,系统多久能返回结果?
- 多少:系统在单位时间内,能同时处理多少请求?
- 多久:系统持续高负载运行几小时、几天后,性能会不会劣化?
用生活类比解释:你开一家餐厅,要关心出菜时间(快不快)、翻台率(多不多)、连续营业几小时后菜品质量和速度是否还稳定(稳不稳)。功能测试只关心菜对不对,不关心这些。
这三个问题对应三类关键指标:响应时间、吞吐量、稳定性。后面我会逐一展开。
1.3 负载测试、压力测试、稳定性测试的分工
很多人把性能测试当成一个大箩筐,其实里面还分不同工种。我在项目里通常会先分清楚:
| 测试类型 | 核心问题 | 典型做法 | 重点观察 |
|---|---|---|---|
| 负载测试 | 系统在预期负载下表现如何 | 逐步增加并发或QPS到目标值,维持一段时间 | 响应时间、吞吐量、错误率 |
| 压力测试 | 系统什么时候扛不住 | 持续加压,超过预期负载,直到系统出现拐点 | 最大TPS、崩溃点、恢复能力 |
| 稳定性测试 | 长时间运行会不会劣化 | 用80%左右的目标容量连续跑8小时、24小时甚至72小时 | 内存泄漏、连接池泄漏、GC频率、慢SQL |
一句话记忆:负载测试是“能不能跑”,压力测试是“跑到什么时候爆胎”,稳定性测试是“整夜跑高速会不会抛锚”。
2. 为什么值得投入:性能测试的商业价值
2.1 容量规划:给“扩不扩容”一个准确答案
做技术的人最烦回答“到时候多买几台机器不就行了”,因为这句话背后没有数据。性能测试能给出的,恰恰是一个可计算的结果。
容量估算逻辑很简单:单机能力 × 节点数 × 冗余系数 = 可承载容量。举例:你的下单接口在压测下单机最多扛400 QPS,线上日常平均负载2000 QPS,大促目标峰值8000 QPS,冗余系数按1.5算,那么应用节点数至少是:
8000 ÷ 400 × 1.5 = 30 台
没有压测数据时,这个数字是拍脑袋拍出来的;有压测数据之后,扩容申请、预算审批、应急预案都有了依据。性能测试在容量规划上的价值,就是让技术决策从“感觉”变成“数据”。
2.2 发布前回归:别让性能问题悄悄积累
性能问题不是每次都像事故那样惊天动地,更多时候是“慢一点,再慢一点”。某次迭代为了加一个展示字段,查询里多了一次大字段读取和排序操作,接口响应时间从80ms涨到300ms。功能测试照样通过,业务操作也正常,但用户体感已经变差了。
这种劣化靠人眼很难发现,靠性能对比很容易发现。我在团队里的做法是:每个版本发布前,对核心接口做一轮基准对比,拿当前版本的TP99和历史基线比,如果劣化超过20%,就必须定位原因再发布。性能测试在这里的角色,相当于代码里的回归测试,专治“静默劣化”。
2.3 用户体验:慢一秒,丢一批用户
做性能测试不能只站在技术角度,还要站在业务角度。大量公开研究都统计过响应时间对用户体验的影响:页面超过3秒,用户流失率会明显上升;支付接口多慢500毫秒,交易失败和用户放弃的占比都会提高。
一个真实的业务场景:某内容社区在做活动页时,客户反馈“页面打不开”,运营和技术排查半天,发现是活动开始后热度超过预期,图片接口没有做缓存,带宽被打满。如果提前压测一下活动页的峰值流量,这个问题完全能在上线前暴露。性能测试表面上是技术投入,实际上是在帮业务节省用户流失带来的真金白银。
2.4 稳定性和资金风险:提前把雷排掉
稳定性测试看起来耗时,但回报率很高。因为很多问题是“慢热型”的:比如内存泄漏,正常跑半小时看不出来,跑两小时后内存曲线一路向上;比如数据库连接池未归还,低峰期不报错,第二天高峰期突然连接耗尽。
这些坑有一个共同特点:越晚发现,修复成本越高。线上故障一旦发生,可能涉及业务中断、用户投诉、紧急回滚,甚至需要运维熬夜处理。性能测试花的是固定的人力和机器时间,换来的是一次上线风险的可控性。
如果团队负责人问你“性能测试有什么用”,不需要讲太多专业术语,把这四点讲清楚就够了:容量规划有依据、发布前能防劣化、体验好不流失、稳定不打折。
3. 从零开始做性能测试:目标、范围、环境、指标
3.1 先定目标:没有目标的压测就是瞎压
我见过很多人拿到压测工具就开跑,跑完一堆图表,却回答不了最基本的问题:这个结果算好还是算坏?
性能测试开始前,一定要把目标写下来,而且写成可量化的格式。比如:
场景:会员中心登录接口 负载模型:日常300 QPS,大促峰值3000 QPS,持续15分钟 指标红线:TP99 < 500ms,错误率 < 0.05%,CPU < 70%这个模板看起来简单,但真正落到纸面上的团队很少。定目标时注意几个细节:
- 目标负载要和真实业务挂钩,不能拍脑袋定“压到1万并发”,要问业务方历史峰值是多少、预计增长多少;
- 指标红线要分主次,至少包含响应时间、错误率、资源使用率三类;
- 目标值要经过评审,开发和运维都认可,否则压测结果出来一定会扯皮。
目标越清晰,后面的脚本设计、数据准备、结果分析才越有方向。性能测试最怕的不是测出问题,而是测完不知道算不算通过。
3.2 圈定范围:核心链路优先,别想一口吃成胖子
有些团队第一次做性能测试就想把所有接口都压一遍,结果脚本写了一个月,环境准备又花两周,最后什么都没测明白。我的建议是:先找二八法则里那20%的核心接口。
怎么找核心接口?有三种方法:
- 看全链路监控里的调用量排名,把Top 10接口拎出来;
- 按核心业务链路走一遍,比如电商必须先覆盖“登录→商品详情→创建订单→支付回调”;
- 问业务方和客服,哪些接口慢了对业务影响最大,比如登录失败用户连门都进不来。
单接口压测用来定位问题,全链路压测用来评估容量。第一次做性能测试,我建议先跑通一个核心链路的全链路压测,哪怕接口数量少一点,也好过铺一大堆脚本最后没结论。
3.3 搭环境:测试环境、预发环境还是生产环境
环境选型直接影响结果可信度。我经常被问“为什么测试环境压测结果和线上差异这么大”,答案往往就在环境和数据上。
| 环境类型 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|
| 测试环境 | 成本低、隔离好、随便折腾 | 配置和数据量远小于生产,结果容易失真 | 脚本调试、缺陷定位 |
| 预发/类生产环境 | 配置接近生产,隔离性好 | 数据不完整,网络策略仍有差异 | 发布前验证、小规模压测 |
| 生产环境 | 最真实,结果可信度最高 | 风险高,可能影响真实用户 | 大促容量评估、全链路压测 |
条件有限时,还有一种折中方案:在生产环境的业务低峰期压测,把压测流量打上特殊标记,配合白名单和熔断预案。这么做不是不行,但一定提前做好风险评估,别省了环境成本、赔上线上稳定性。环境选择的优先级永远是:先保证结果有参考价值,再考虑成本。
3.4 指标设计:别只看平均值,长尾才是魔鬼
性能指标很多,但第一次做性能测试,掌握下面这张表就够了:
| 指标 | 口径说明 | 主要用途 |
|---|---|---|
| 响应时间(RT) | 平均、TP50、TP90、TP95、TP99 | 评估用户体验,重点关注高百分位 |
| 吞吐量(QPS/TPS) | 每秒请求数或事务数 | 容量评估、集群规模估算 |
| 错误率 | HTTP 5xx、超时、业务失败率 | 可用性红线 |
| 资源利用率 | CPU、内存、磁盘IO、带宽、连接数 | 瓶颈定位 |
| 中间件指标 | 连接池使用率、GC频率与耗时、线程数 | 稳定性分析 |
为什么要强调TP99而不是平均值?因为平均值太好骗了。100个请求里99个都很快,只有1个特别慢,平均值可能依然好看,但那个最慢的用户会直接投诉。现实场景里,用户感受到的往往是“最差的那一次体验”,而不是“平均体验”。所以制定指标红线时,我建议至少写三条:TP99、错误率、某个资源使用率上限。
4. 实操中的高频坑:帮你少走三个月弯路
4.1 脚本看着简单,细节全是坑
压测脚本不是写完就能用。我在评审脚本时,每次都会重点问四个问题:
- 参数化做了没有?如果所有请求都用同一个用户、同一个商品、同一个订单,缓存命中率会高到失真,数据库也无法模拟真实压力;
- 关联做了没有?很多接口需要先登录拿token,再在后续请求里带token,漏掉关联会导致大量401,错误率飙升,但系统本身没问题;
- 思考时间加了没有?真实用户会有浏览停顿,如果不加思考时间,并发会同时怼到系统上,容易把连接池瞬间打满,测出虚假的极限值;
- 断言写了没有?只检查HTTP 200不够,业务可能返回成功状态码但内容不对,必须对关键业务字段做断言。
这四类问题一个不注意,压测结果就没法看。
4.2 压测时不看监控,等于闭眼开车
曾经有个同事压测完拿数据给我看,说系统CPU才30%,但响应时间很高。我打开监控一看,压测机本身CPU已经100%了,压力根本打不进去。这就是典型的“只盯服务端、没盯客户端”。
压测过程中至少同时盯这几层监控:
- 应用层:CPU、内存、GC频率与耗时、线程数、连接池使用率;
- 数据库层:慢查询、连接数、锁等待、磁盘IO;
- 中间件层:网关带宽、消息队列堆积数、缓存命中率;
- 压测引擎层:压测机CPU、内存、网络带宽,确保压力源不是瓶颈。
我的操作习惯是:压测开始前先采集5分钟基线,压测过程中按1分钟粒度记录关键指标,结束后再采集5分钟,看指标是否能回落。基线是对比的前提,没有基线就等于没有参照物。
4.3 脏数据不处理,报表就没法看
压测一定会产生大量脏数据:重复订单、假用户、堆积的日志。如果不做处理,轻则占用磁盘空间,重则污染下一次测试结果。我用过的可靠方法:
- 压测流量统一带特殊前缀或事务ID,方便识别和清理;
- 数据构建脚本和清理脚本成对维护,每次压测跑完后短时间内清干净;
- 压测数据尽量使用独立库、独立账号、独立缓存key,避免污染生产数据;
- 接口设计上尽量支持幂等,避免重复请求造成库存、余额等状态被扣穿。
曾经有一次压测完忘了清理,第二天生产环境的下单表多了几十万条测试订单,运营导出报表时崩溃了。从那以后,我把“清除脏数据”写进了压测结束的强制检查清单。
4.4 瓶颈可能藏在你想不到的地方
有一次压测,应用和数据库指标都很健康,但QPS无论如何过不了2000。排查到最后,是压测机和服务器之间的网络带宽被打满了。后来算了一笔账:单请求平均2KB,想支持10万QPS,理论带宽就需要接近2GB,普通千兆网卡根本扛不住。
做容量评估时,别只算应用层的CPU和内存,也要算网络带宽、连接数、DNS解析耗时、防火墙策略这些容易被忽略的层。性能瓶颈往往是“木桶效应”,最短的那块板决定整体能力。
4.5 生产环境到底能不能压
生产环境压测最有效,也最危险。没有条件的团队,不建议轻易碰生产;有条件时,也得按规矩来:
- 选择业务低谷期,预留足够的回滚时间;
- 压测流量打特殊标记,和真实流量从日志层面就能区分;
- 提前配置好告警和熔断,一旦指标超出阈值,自动终止压测;
- 提前通知运维、研发、业务方,形成共识和应急预案。
我见过太多团队直接在白天高峰生产环境压测,结果把线上用户也一起压进去了。性能测试的目的是暴露风险,不是制造事故。
5. 团队落地:从一次性的“跑压测”变成常态化能力
5.1 谁来发起,怎么分工
性能测试最怕变成一个人的任务。一个人在角落里默默压测、默默写文档,最后没人信,也没人跟进。比较好的组织方式是:
- 技术负责人发起,明确性能目标是团队目标;
- QA负责压测方案、脚本和执行;
- 研发负责提供代码层面的分析、配合定位瓶颈;
- 运维负责环境、监控和容量数据的采集;
- 业务方负责提供真实的流量预估和用户行为模型。
团队如果刚开始没有专职性能测试工程师,可以先从核心链路做一次完整压测作为“样板工程”。样板一旦跑通,团队看到了实际效果,后面推广起来就顺得多。
5.2 工具选型:先用手边会的,别迷信商业工具
工具不是越贵越好,关键是团队能用起来。下面是一些常见的开源方案:
| 工具 | 脚本方式 | 特点 | 适合场景 |
|---|---|---|---|
| JMeter | Java/图形化配置 | 插件丰富,资料多,适合多接口和分布式压测 | 大多数团队的入门首选 |
| k6 | JavaScript | 云原生友好,适合写进CI流水线 | 持续集成、轻量压测 |
| Locust | Python | 协程并发,复杂场景脚本可读性好 | 需要灵活编写压测逻辑时 |
| Gatling | Scala DSL | 报表美观,代码化管理 | 对报告质量要求较高的团队 |
| wrk/vegeta | 命令行 | 轻量简单,适合单接口基准测试 | 快速压测、冒烟验证 |
我的建议是:第一次做性能测试,用自己最熟悉的工具就好,工具的价值在于帮你准确模拟压力和数据采集,不在于用得多炫。先把JMeter或k6跑明白,再考虑平台化建设。
5.3 把性能回归塞进持续集成
性能测试不应该只在上线前做,更应该在每次代码变更时做。我习惯把性能回归分成三个级别:
- 每次构建:对核心接口跑一个低并发的基准测试,只要TP99明显劣化就失败,相当于性能冒烟;
- 每日或每周:跑一轮中等负载的核心接口回归,和上一版本对比,看关键指标是否劣化;
- 大版本或大促前:跑全链路压测和稳定性长跑,输出完整的容量报告。
性能回归不是要每次都压到极限,而是要早发现趋势变化。哪怕只是“比昨天慢了10%”,早发现也比上线后才发现要好得多。设定一个简单的规则:核心接口TP99劣化超过20%,必须定位原因才能合入。
5.4 报告怎么写,领导才愿意看
写过很多性能测试报告,最后发现,大家愿意看的是结论和行动项,不是几十张曲线图。报告至少回答三个问题:
- 能不能上线或者能不能接活动流量?
- 系统最大容量是多少?
- 哪些瓶颈要先处理,大概需要多少人力和机器?
用表格呈现最清晰:
| 场景 | 目标TPS | 实测TPS | 结论 | 主要瓶颈 | 建议动作 |
|---|---|---|---|---|---|
| 下单链路 | 3000 | 2800 | 不达标 | 数据库CPU 90%,存在慢SQL | 增加联合索引;订单表分库分表;扩容2个数据库节点 |
写报告时记住一句话:图表是证据,不是结论。你要先给结论,再用图表支撑,否则再漂亮的报告都会被当成技术自嗨。
6. 系列开篇之后,说几句我的个人体会
做了这么多年性能测试,我最大的感受是:最难的部分从来不是工具,而是让团队相信这些数据有意义。性能测试做成功一次的关键,不是压测脚本多完美,而是先找到一个真实问题,并把它修掉。哪怕第一次只发现一个慢SQL,也比什么都没有强。
我现在接到一个新的性能测试任务,第一件事不是打开压测工具,而是先聊清楚“为什么压、压多大、压挂了怎么办”。这三个问题没答案,后面做得越多偏得越远。
作为“性能测试实战全流程”系列的第一篇,我把“为什么做”这个问题先讲透,后面的内容才好展开。下一篇会进入具体的测试方案设计,包括怎么设计场景模型、怎么准备数据、怎么分析监控曲线。最后再给新手一个小建议:不要等公司有大促才想起性能测试,现在就拉一个开源项目,从100个并发开始跑,先学会看懂指标,再谈复杂的方法论。