压力测试的流程与实施步骤
压力测试不是随便找个工具点两下就完事的。我见过太多团队上来就开跑,跑完拿一堆数据却不知道瓶颈在哪,浪费了时间还没解决问题。说白了,压力测试有一套固定的套路,按步骤走才能少踩坑。下面我把这套流程拆开讲清楚。
1. 前期准备与目标定义
动手之前先问自己三个问题:
- 测什么——核心业务接口还是全链路?
- 目标多少——预期并发用户数、TPS、响应时间P99?
- 资源够吗——压测机、网络带宽、监控系统是否就绪?
我个人习惯在项目启动会上就和开发、运维一起敲定这些指标。举个例子,有一次做支付系统的压力测试,业务方说要支持1000 TPS,但实际压到800 TPS时响应时间已经飙到5秒了。为什么?因为他们在需求里漏写了数据库连接池的限制。嗯,这里要注意:目标定义必须包含资源上限和容忍阈值,否则测出来的结果没有参考意义。
2. 场景设计与脚本开发
场景设计是压力测试的灵魂。你得模拟用户真实行为,而不是让所有线程同时调同一个接口。我把场景分成两类:
| 场景类型 | 特征 | 常见用途 |
|---|---|---|
| 阶梯加压 | 每30秒增加100并发,持续观察 | 找拐点、定位瓶颈出现时的并发量 |
| 突发冲击 | 直接拉满到目标并发,持续几分钟 | 验证容错与降级策略是否有效 |
| 混合负载 | 按比例混合不同接口,保持真实流量比例 | 全链路压测,模拟线上真实场景 |
脚本开发时,我记得有个坑:参数化不到位。比如用JMeter压测登录接口,如果每个线程都传同一个手机号,后端会走缓存或限流,结果完全失真。你想想看,这种数据根本不能用来评估系统容量。
下面是JMeter中一个简单的阶梯加压脚本片段(仅做示意):
// 使用Stepping Thread Group
线程数:100
初始延迟:5秒
每次增加:10个线程
每次增加间隔:10秒
持续时间:120秒
3. 执行与监控
执行阶段不是点一下“开始”就去喝咖啡。你必须在旁边盯着三件事:
- 压测机自身资源——如果CPU被打满,测出来的延迟是假的
- 目标服务器指标——CPU、内存、磁盘I/O、网络带宽、连接数
- 应用层指标——错误率、响应时间分布、线程池队列长度
我建议压测机和目标机之间留出至少2倍冗余。有一次我贪方便,在本地笔记本压服务器,结果笔记本风扇狂转,请求还没离开网卡就被本机进程抢了CPU……这种数据你敢信吗?
4. 结果分析与瓶颈定位
压力测试出结果后,别急着调优。先画一张拐点图:横轴是并发数,纵轴是TPS或响应时间。你会发现大部分系统都有明显的“断崖式下跌”点。那个点就是瓶颈。
定位瓶颈时依照 木桶理论:
- 看CPU使用率——如果单核打满,可能是代码层面的计算瓶颈
- 看IO等待——如果iowait高,大概率是磁盘或数据库慢
- 看网络重传率——如果重传包突然增多,说明带宽或连接数满了
- 看GC频率——Young GC超过5次/秒就要警觉
说个真实案例:我以前测一个电商秒杀接口,压到600 QPS时TPS突然掉到零。看监控发现Redis连接数被耗尽,原因是代码里每次请求都new了一个Jedis实例,没使用连接池。这种问题在代码审查时很难发现,压力测试一跑就原形毕露。
5. 调优与再验证
找到瓶颈后开始调优,但调优后必须做回归验证。压测流程是循环的:调优→再测→看数据→再调。
我习惯把每次调优前后的指标记在同一张表里:
| 调优动作 | 压测前TPS | 压测后TPS | 响应时间P99变化 |
|---|---|---|---|
| 增加连接池大小 | 800 | 950 | 从1200ms降到800ms |
| 添加Redis缓存 | 950 | 1300 | 从800ms降到350ms |
直到所有指标达到目标值,或者确认当前架构已经没办法再优化(比如单机CPU已经100%,必须上分布式)。这时压力测试才算阶段性结束。
下面我把整个流程画成一张图,方便你记在脑子里。
这张图里有个细节:从调优阶段画了一条虚线回到结果分析阶段。为什么?因为调优后必须重新压测并分析结果,而不是直接跳到下一轮。我曾经见过团队改完代码后只跑一次就宣告成功,结果上线后QPS一高又崩了——原来是修复了一个瓶颈,又暴露了另一个瓶颈。压力测试是循环迭代的,直到所有指标都满足目标,或者你确认当前架构确实到了天花板。
嗯,以上就是压力测试的完整流程。记住:没有标准化的流程,压测数据就是一堆废纸。按这五个步骤走,你至少不会在方向上犯错。实战中每个阶段都有很多细节陷阱,后面几章我会逐个展开讲。