上线前为什么值得做一次正经压测
很多人把“压测”理解成发布前临时跑一个脚本、看着数字还行就通过。但压测真正的价值是提前暴露瓶颈:一台 2 核 4G 的入门云服务器,50 并发时表现良好,加到 300 并发延迟可能直接翻十倍。与其让第一个真实用户来发现这个问题,不如在上线前用脚本把它逼出来。
下面这份清单把“压测”拆成四件事:定标准、选工具、跑真实场景、看监控证据。
第一步:先把“及格线”写下来
没有验收标准的压测等于没测。建议在压测前把下面这套阈值写进团队的验收文档,而不是压完再“看情况”:
| 指标 | 健康线 | 警戒线 | 失败线 |
|---|---|---|---|
| CPU 峰值 | < 60% | 80% | 90% 持续 5 分钟 |
| 内存峰值 | < 70% | 85% | 90%+ 持续上涨不回落 |
| 95 分位响应时间 | < 400ms | 800ms | 1200ms |
| 错误率(5xx/超时) | < 0.1% | 0.5% | 1% |
| 磁盘 I/O | 无排队 | 偶发阻塞 | 持续阻塞 |
需要注意,CPU 85%、内存 90% 这类数字不是“推荐负载”,而是“请立刻去查”的报警阈值。压测要回答的问题是“这台机器在什么负载下会开始变差”,而不是“它最多能扛多少”。
第二步:选对工具
常见压测工具有三档,按你的场景挑:
| 工具 | 特点 | 适合场景 | 学习成本 |
|---|---|---|---|
| wrk | 单机高并发、基于 C,性能极高 | 快速压测静态接口、Nginx | 低 |
| k6 | 脚本化、支持场景编排和阈值断言 | 模拟真实用户路径、CI 集成 | 中 |
| Locust | Python 编写、支持分布式 | 复杂业务流程、团队熟悉 Python | 中 |
个人站和中小项目,用 k6 就够了:能写脚本模拟登录、浏览、下单这类真实路径,还能在脚本里直接写 thresholds,让压测失败自动报红。一个最小可用的 k6 脚本长这样:
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 50 },
{ duration: '2m', target: 100 },
{ duration: '2m', target: 300 },
{ duration: '2m', target: 500 },
{ duration: '2m', target: 0 },
],
thresholds: {
http_req_failed: ['rate<0.005'],
http_req_duration: ['p(95)<800'],
},
};
export default function () {
const res = http.get('https://your-site.example/');
check(res, { 'status is 200': (r) => r.status === 200 });
sleep(1);
}
这段脚本会分四档把并发从 50 拉到 500,再缓缓降回 0,同时用两个阈值兜底:错误率低于 0.5%、95 分位响应低于 800ms。中途一旦越线,k6 会直接按失败退出。
第三步:按“真实访问”而不是“首页”来压
只压首页是最常见的偷懒。真实的访问是混合的:静态资源走 CDN、商品列表走缓存、下单接口直接打数据库。建议至少覆盖三类请求:
- 静态资源(图片/CSS/JS):主要验证 CDN 回源和带宽;
- 读接口(列表、详情):验证数据库查询和缓存命中;
- 写接口(下单、提交表单):验证事务、锁、磁盘 IO。
给写接口压测时,别忘了同时观察慢查询日志和连接池。很多压测“失败”其实不是机器不行,而是数据库连接数被写满,请求全部排队等连接。
第四步:用监控数据定位瓶颈
压测的同时要开着监控看。下面是一张常见的“症状 → 瓶颈”对照表:
| 症状 | 大概率瓶颈 | 看哪里 |
|---|---|---|
| 响应慢、CPU 高 | 应用逻辑或数据库查询 | top、慢查询日志 |
| 内存持续上涨不回落 | 内存泄漏 | 进程 RSS、GC 日志 |
| 磁盘 I/O 阻塞 | 慢查询写放大、日志刷盘 | iostat、iotop |
| 带宽先打满 | 静态资源未走 CDN | iftop、CDN 回源统计 |
| 响应抖动、偶发超时 | 连接池耗尽、GC 停顿 | 连接池指标、GC 曲线 |
定位时记住一个原则:一次只改一个变量。把 Nginx 缓存打开、数据库加索引、PHP 换成 OPcache 这些改动混在一起做,压完你根本不知道是哪一项起了作用。
一个真实场景:双 11 前的临时加购高峰
假设你运营一个面向国内用户的电商小程序,往年双 11 当天晚 8 点会迎来一次并发陡增,平时峰值只有 200,当天可以冲到 1200。压测时就不要只按“日常 200 并发”来测,而是把时间拉到活动当晚的流量曲线:前 5 分钟快速爬升、高峰维持 30 分钟、尾段回落。
这种测试通常会暴露两类问题:一是数据库连接池按日常规模配置,高峰时连接被抢光,读接口大量超时;二是静态资源没有单独走 CDN 域名,图片请求把出口带宽打满,拖累接口响应。两者都能在压测报告里提前定位,而不是等用户截图投诉。
压测之后要交付什么
压测不只是为了“通过”,还要留下证据。一份合格的压测报告至少包含:
- 环境说明:机器规格、软件版本、压测工具与参数;
- 分阶段结果:每个并发档位的 QPS、P95/P99 延迟、错误率;
- 瓶颈清单:按影响排序的瓶颈和对应的证据(监控截图、慢查询);
- 建议动作:每一条建议都要能对应到具体的改动,而不是“建议优化性能”。
参考:k6 官方文档 https://grafana.com/docs/k6/latest/ ,wrk 仓库 https://github.com/wg/wrk
常见误区
最后列几个经常翻车的地方:拿本机压测代替线上(本机网络和缓存环境完全不同);只看平均响应时间不看 P95(平均被少数快请求拉低);压完不看慢查询(响应时间上升很大一部分都来自数据库);把压测机放在和被压服务器同一台机器上(互相干扰,结果失真)。