本文要点
- 用
docker起一个nginx:alpine容器当压测目标,避免污染本机环境 ab用-n指定总请求数、-c指定并发数,重点看Requests per second与Time per request- 加上
-k开启 keep-alive 后吞吐量可提高数倍,对比测试最能说明连接复用的价值 wrk用线程 + 连接数的模型,配合--latency输出延迟分位,适合长时间持续压测- 压测结论依赖机器与网络,重点是横向对比而非绝对值;测带宽/负载均衡等场景应结合其他工具
为什么要做 HTTP 压测
上线前的性能评估、配置调优后的效果对比、确定一台机器的承载上限,都需要"用数据说话"。HTTP 压测工具的作用就是模拟大量并发请求打到服务上,输出吞吐量、响应时间、失败率等指标,帮我们回答三个问题:能扛多少 QPS、响应有多快、瓶颈在哪里。
本文会用 ApacheBench(ab) 和 wrk 两种最具代表性的工具,在一台真实的 Ubuntu 24.04 服务器上完成一轮完整的压测。前者历史悠久、开箱即用,适合快速摸底;后者基于事件驱动模型,高并发下的表现更接近真实负载,适合深入观察延迟。
准备压测环境
压测的是本地服务,为了不污染系统,我用 Docker 直接起一个轻量 nginx 作为被测对象,把容器的 80 端口映射到宿主机的 8080:
docker run -d --name web-bench -p 8080:80 nginx:alpine先确认服务已就绪:
$ curl -s -o /dev/null -w "HTTP %{http_code} | size %{size_download}B\n" http://127.0.0.1:8080/
HTTP 200 | size 896B返回 200,页面 896 字节,这就是我们后面要反复打的"靶子"。注意压测全部走 127.0.0.1 回环地址,避免公网链路干扰,这样测出来的是纯服务性能。
提醒:被测页面的体积会直接影响测试结果。同样的服务,返回 896 字节首页和返回 2MB 文件,QPS 可能差一个数量级。做对比测试时务必保持目标一致。
ApacheBench 入门
ab 是 Apache 自带的小工具,Ubuntu 上装在 apache2-utils 包里:
sudo apt-get install -y apache2-utils安装后直接就能用 ab -V 查看版本:
$ ab -V
This is ApacheBench, Version 2.3 <$Revision: 1903618 $>第一次压测
ab -n 2000 -c 50 http://127.0.0.1:8080/-n 2000 表示总共发送 2000 个请求,-c 50 表示同时维持 50 个并发连接。下面是完整输出:

输出里最重要的几行:
- Concurrency Level: 50——本次压测的并发数,即同时有 50 个连接。
- Requests per second: 5922.33——每秒完成的请求数,也就是日常说的 QPS,性能的核心指标。
- Time per request: 8.443 ms——平均每个"用户"完成一次请求花费的时间(同等并发下单次请求的总耗时)。
- Time per request: 0.169 ms (mean, across all concurrent requests)——按总耗时除以全部请求数得出的均值,比上面那个更有参考意义。
- Transfer rate: 6529.60 Kbytes/sec——网络吞吐,受响应体大小影响。
- Percentage of the requests served within a certain time——响应时间分布,50% 的请求在 8ms 内完成、99% 在 16ms 内完成,是判断"尾部延迟"的关键。
这次实测单台 1.9G 内存的小型云主机,nginx 大约能扛 5900 QPS,平均单请求 8.4ms,Failed requests 为 0,表现符合预期。
常用参数
ab 的参数不多,日常够用的就这几个:
| 参数 | 含义 | 示例 |
|---|---|---|
-n | 总共发多少个请求 | -n 10000 |
-c | 并发连接数 | -c 100 |
-k | 启用 HTTP Keep-Alive,复用连接 | -k |
-H | 添加自定义请求头 | -H "Authorization: Bearer xxx" |
-p | 发送 POST 请求并用文件提供 body | -p post.json |
-T | 指定 Content-Type | -T application/json |
-t | 按时长压测(如 -t 10 跑 10 秒) | -t 10 -n 1000000 |
注意默认情况下 ab 每发一个请求就新建一个 TCP 连接、用完就断开。这在真实世界里并不常见,因为浏览器和 HTTP 客户端都会复用连接。想让压测更贴近生产环境,就得加上 -k。
Keep-Alive 的巨大影响
用同样的参数只加一个 -k 再跑一次:
ab -n 2000 -c 50 -k http://127.0.0.1:8080/
对比肉眼可见:
| 指标 | 不带 -k | 带 -k |
|---|---|---|
| Requests per second | 5922 | 15381 |
| Time taken for tests | 0.338 s | 0.130 s |
| Time per request (mean) | 8.443 ms | 3.251 ms |
| 中位延迟 (50%) | 8 ms | 3 ms |
吞吐量从 5922 提升到 15381 QPS,接近 2.6 倍。原因很简单:HTTP/1.1 下每次请求都要经过 TCP 三次握手 + TLS 握手(走 HTTPS 时更明显),而 keep-alive 复用连接省掉了这部分开销。输出里也多了 Keep-Alive requests: 2000 这一行,表示全部请求都走了复用连接。
调优经验:如果线上服务本来就开启了 keep-alive(nginx 默认keepalive_timeout65s),压测却不加-k,测出的数字会明显低估真实容量。两种都测一遍能顺便验证"连接复用"这个优化项到底值多少。
wrk:新一代压测工具
wrk 用 C 语言 + epoll/kqueue 事件驱动模型实现,单机可以轻松撑起几十万并发连接,输出也更简洁。Ubuntu 24.04 的仓库里直接有:
sudo apt-get install -y wrk运行压测
wrk -t2 -c50 -d5s --latency http://127.0.0.1:8080/-t2 用 2 个线程、-c50 维持 50 个连接、-d5s 持续压 5 秒,--latency 额外输出延迟分布:

wrk 的输出分为三块:
- Thread Stats——每个线程的统计。
Req/Sec 8.54k表示每个线程每秒约处理 8.5k 请求;Latency列给出平均、标准差和最大值,+/- Stdev是"多少数据落在均值一个标准差内"的比例。 - Latency Distribution——延迟分位:50% 的请求 2.84ms 内完成、90% 在 4.67ms、99% 在 6.67ms。相比 ab 的百分比表,这里更直观。
- Requests/sec: 16975.96——总体 QPS,这是最核心的结论。5 秒内完成了 84929 个请求,平均每秒约 1.7 万。
wrk 内部自动复用连接,所以它的数字和 ab + -k 接近(本例 16975 vs 15381),而不是和 ab 默认模式(5922)接近。
线程、连接与时长
wrk 的参数模型和 ab 不同,它不是"总请求数",而是"每次发 N 秒":
| 参数 | 含义 | 说明 |
|---|---|---|
-t | 线程数 | 通常设为 CPU 核数,启动 -tN 会 fork N 个线程(实际还有主线程) |
-c | 连接数 | 总连接的开启的连接,会均分到每个线程 |
-d | 持续时间 | 数值支持单位,5s、30s、2m |
--latency | 打印延迟分位 | 建议始终加上,否则看不到延迟分布 |
-s | 加载 Lua 脚本 | 支持自定义请求、签名鉴权等高级场景 |
压测时建议先小规模(-t1 -c10 -d3s)快速确认服务正常,再加大到目标负载,避免一开始就把服务打挂。
观察"平台期"
真实的压测不只是看一个峰值,更要观察随着并发上升 QPS 的曲线。把并发从 50 拉到 200、时长拉到 10 秒,看看这台小主机的表现:
wrk -t4 -c200 -d10s --latency http://127.0.0.1:8080/实测对比很有意思:
| 并发 | QPS | 平均延迟 | 99% 延迟 |
|---|---|---|---|
50(-c50) | 18011 | 2.78 ms | 6.43 ms |
200(-c200) | 16900 | 11.84 ms | 24.97 ms |
并发提高到 4 倍,QPS 反而掉了约 6%,而延迟涨了 4 倍多——这就说明服务已经逼近处理上限,瓶颈通常在 CPU 单核、worker 数量或数据库连接这类资源上。这也解释了为什么压测必须带着延迟一起看:光看吞吐高没有意义,当并发上去后台延迟陡增时,用户体验已经崩了。
ab 与 wrk 对比与选择
| 维度 | ab | wrk |
|---|---|---|
| 模型 | 单线程,每请求独占连接(除非 -k) | 事件驱动,线程 + 数万连接 |
| 安装 | apache2-utils | wrk 包 |
| 请求控制 | 按总数 -n 或按时间 -t | 按时间 -d |
| 高并发能力 | 一般,并发高时有偏差 | 强,适合大并发 |
| 延迟统计 | 百分位表(50%~100%) | 分位分布 + 线程统计 |
| 自定义请求 | -p body / -H 头 | Lua 脚本,功能更强 |
| 典型场景 | 快速摸底、简单验证 | 持续压测、详细延迟分析 |
选择建议:快速验证服务通不通、功能正常不正常,用 ab 一条命令就够;要评估服务在高并发、长时间下的承载能力和延迟表现,用 wrk;两者互补,可以都装。
压测注意事项
- 目标要单一:压测对象只放一个 nginx/应用容器即可,别让系统的其他负载干扰结果;同一轮对比必须保证环境不变。
- 先本机再跨机:本机回环测的是服务纯性能,适合对比调优;跨机器压测才能反映网络栈、公网链路的真实表现。
- 控制量级:
-c、-d从小到大逐步加,视服务能力而定,避免稀少的云主机瞬间被打到内存或带宽耗尽。 - 读懂失败:
Failed requests不为 0 或 wrk 输出Socket errors时,要区分是超时(服务慢)还是连接被拒(并发上限),排错方向完全不同。 - 关注尾部延迟:平均延迟漂亮不代表体验好,
99%/99.9%分位才是用户真正感知到的"卡不卡"。 - 数据只做参考:云主机的 CPU 会因邻居抢资源波动,同一命令每次跑出的数字都不同。结论看趋势和量级,别纠结 ±10% 的差异。真实峰值压测建议用 hey 或 Apache JMeter 做更大规模的验证。
小结
压测不是跑一条命令发一堆请求那么简单,它的核心是用对工具、看懂指标、做好对比。这一次演示覆盖了:
- 用 Docker 快速搭一个干净的压测目标;
- 用
ab -n -c快速摸底,读懂 QPS、时延、分位这些关键输出; - 用
-k验证 keep-alive 对吞吐量近 2.6 倍的提升; - 用
wrk -t -c -d做持续压测,结合延迟分位判断服务是否到达平台期。
当你需要回答"这台机器能扛多大流量"时,从这两条命令开始:
ab -n 5000 -c 50 -k http://127.0.0.1:8080/
wrk -t2 -c50 -d10s --latency http://127.0.0.1:8080/同样是这台小主机,ab -k 能到每秒 1.9 万,wrk 能到每秒 1.8 万左右,两者互相印证,结论就可靠了。
评论 (0)
暂无评论,快来抢沙发吧!