如何使用wrk进行网站压力测试?并发参数与结果解读

给网站做压测,绕不开工具选择。ab 简单,但单线程、能力有限,稍微大一点的机器就跑不满了;JMeter 功能全,但要装 Java、学 GUI,偏重。wrk 正好卡在中间:命令行、多线程、基于事件驱动,单机就能压出很高的并发,输出还带延迟分布,是很多运维和开发做 HTTP 压测的首选。

这篇文章讲清楚 wrk 怎么用:怎么安装、参数各是什么含义、结果怎么读、怎么用脚本发 POST 请求、和 ab 有什么区别、以及那个最容易被忽略的坑——压测客户端自己先成了瓶颈。文中数值为经验量级,以你实际环境为准。

一、wrk 为什么值得用

wrk 的核心特点是多线程 + 事件驱动(epoll/kqueue)。它可以开多个线程,每个线程内部用非阻塞 IO 处理大量连接,因此单机就能发起很高的并发,比 ab 这种"一个线程一个连接"的模式强得多。

主要优势:

  • 能压出高并发,适合现代多核服务器。
  • 自带延迟分布统计(配合 --latency),能看到 P50/P90/P99。
  • 支持 Lua 脚本,可以自定义请求方法、Body、Header、动态参数。
  • 命令行轻量,容易脚本化和自动化。

适合场景:HTTP/HTTPS 接口压测、找单机 QPS 上限、验证性能优化效果、上线前容量评估。

二、安装

wrk 在部分发行版默认源里没有,两套做法。

# Debian / Ubuntu:部分版本源里有 wrk,可先尝试
sudo apt update && sudo apt install -y wrk

# RHEL / CentOS / Rocky / AlmaLinux:一般需要从源码编译
sudo dnf install -y git gcc make openssl-devel
# CentOS 7
sudo yum install -y git gcc make openssl-devel

# 源码编译(两套发行版通用)
git clone https://github.com/wg/wrk
cd wrk
make
sudo cp wrk /usr/local/bin/
wrk --version    # 验证安装

编译依赖 OpenSSL 开发包(HTTPS 支持)。如果 make 报找不到 ssl,检查 openssl-devel(RHEL 系)或 libssl-dev(Debian 系)是否装好。

三、常用参数

wrk [选项] 
参数 含义 建议
-t 线程数 一般设为 CPU 核数或核数×1~2
-c 并发连接数 要测的并发量,需大于等于线程数
-d 持续时长 至少 30s,稳态建议 1~3 分钟
--latency 打印延迟分布 强烈建议加上
-s 指定 Lua 脚本 发 POST、带参数时用
-H 添加请求头 如 -H "Authorization: Bearer x"
--timeout 请求超时 默认 2s,可调
-R 每连接每秒请求数 限速用(部分版本支持)

一个常规调用:

# 4 线程、100 并发、持续 30 秒、输出延迟分布
wrk -t4 -c100 -d30s --latency http://127.0.0.1:8080/

调参经验:-t 不要超过压测机核数太多;-c 要明显大于 -t 才有意义(否则线程空转);-d 太短测的是预热阶段,没有参考价值。

四、结果怎么读

典型输出:

Running 30s test @ http://127.0.0.1:8080/
  4 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    12.34ms   3.21ms  120.00ms   87.50%
    Req/Sec   850.00    120.00   980.00    75.00%
  Latency Distribution
     50%    11.00ms
     75%    13.00ms
     90%    16.00ms
     99%    25.00ms
  102000 requests in 30.00s, 25.50MB read
  Socket errors: connect 0, read 5, write 0, timeout 0
Requests/sec:   3200.00
Transfer/sec:    870.00KB

逐项解读:

  • Requests/sec:这是 QPS,最核心的吞吐指标。
  • Transfer/sec:吞吐带宽,判断是否撞带宽瓶颈。
  • Latency Avg / Stdev / Max:平均、标准差、最大响应时间。Stdev 相对 Avg 很大,说明响应时间不稳定。
  • Latency Distribution:延迟分位数。P99 是最该关注的——它代表最慢那 1% 用户的体验。平均值好看但 P99 很差,说明有长尾问题。
  • Socket errors:连接、读、写错误和超时。任何非零都要查。connect 错误多可能是端口耗尽或服务端拒绝;timeout 多说明服务端处理不过来或网络差。
  • requests in ... s:总请求数和总时长,用来核对。

五、用 Lua 脚本发 POST 与动态参数

默认 wrk 发 GET。要发 POST、带 JSON Body,用脚本:

-- post.lua
wrk.method = "POST"
wrk.body   = '{"id":1,"name":"test"}'
wrk.headers["Content-Type"] = "application/json"
wrk.headers["Authorization"] = "Bearer your-token"
wrk -t4 -c100 -d30s --latency -s post.lua http://127.0.0.1:8080/api/create

要每次请求用不同参数(避免缓存干扰),用 request() 或 init()/setpath:

-- rand.lua:每个请求带随机 id
request = function()
  local id = math.random(1, 100000)
  return wrk.format(nil, "/api/item?id=" .. id)
end
wrk -t4 -c100 -d60s --latency -s rand.lua http://127.0.0.1:8080/

用随机参数能更真实地反映生产流量,也能避免所有请求命中同一条缓存记录导致结果虚高。

六、和 ab 的对比

维度 wrk ab
并发模型 多线程 + 事件驱动 单线程,进程/线程模型
能否压高并发 能,适合多核 受限,单机上限低
延迟分布 有(P50/P90/P99) 只有部分统计
脚本扩展 Lua,灵活 基本不支持
上手难度 低 很低
适用 现代多核服务器、接口压测 快速小规模验证

结论:小规模快速验证用 ab,正式压测用 wrk。ab 最大的局限是单线程,压测机上它自己先到瓶颈,容易低估服务端能力。

七、注意事项:压测客户端可能先成瓶颈

这是 wrk 使用中最重要的提醒:wrk 再强,压测机资源也是有限的。

  • CPU 不够:wrk 线程会和 -t 匹配。压测机 CPU 跑满,QPS 就被压测机限住了。
  • 端口/连接耗尽:高并发下客户端大量 TIME_WAIT,可能耗尽本地端口。可临时调整内核参数,或让服务端支持长连接。
  • 网络带宽:响应体大时,压测机网卡可能先被打满。看 Transfer/sec 和压测机网卡。
  • 压测机与被测机分离:绝对不要把 wrk 和被压服务放同一台机器,两者抢资源,结果毫无意义。

判断压测机是否成瓶颈:压测时看压测机的 top、ss -s、网卡流量。若压测机 CPU 接近满而服务端还有余量,就是它的问题,需要换更强压测机或分布式压测。

八、阶梯加压找单机拐点

单跑一个并发值只能得到一个点,真正有用的是"加压曲线"——随着并发上升,QPS 和响应时间怎么变。

# 阶梯加压:从 50 并发加到 800,观察 QPS 与延迟变化
for c in 50 100 200 400 800; do
  echo "===== 并发 $c ====="
  wrk -t4 -c$c -d30s --latency http://127.0.0.1:8080/api/hot
  sleep 5
done

把每轮的结果记成一张表:

并发 QPS Avg 延迟 P99 延迟 Socket errors
50 2100 23ms 60ms 0
100 3200 31ms 110ms 0
200 3500 57ms 260ms 0
400 3400 118ms 800ms 12
800 2900 276ms 2200ms 340

判读方法:

  • QPS 达到平台并开始回落,同时 P99 明显变长、错误出现,这个拐点就是单机上限。上表里 200 并发附近是拐点,400 之后已经在劣化。
  • 取拐点前的健康并发(这里是 100~200)作为推荐工作区间,而不是取极限值。
  • 拐点之后 QPS 下降,是因为资源饱和导致排队,请求还没处理完就超时,属"过载自噬"。

这个拐点值,就是容量规划里"单机可承载 QPS"的来源。

九、几个常见误区

误区一:只看 Requests/sec,不看延迟。 QPS 高但 P99 已经到秒级,用户照样受不了。要 QPS 和延迟一起看。

误区二:并发拉到最高。 并发越高越能压出上限,但也越容易把服务压垮、产生大量错误,测出的数据反而没有参考价值。要从低到高阶梯加压。

误区三:压测机和服务端放一起。 两者抢 CPU 和网络,测出来的数字毫无意义,必须分开部署。

误区四:不考虑真实流量特征。 只压一个静态接口、只发同一请求、带满缓存,结果会虚高。用 Lua 脚本模拟真实请求分布和随机参数,结果才有意义。

误区五:测完不记录环境信息。 不记机器配置、软件版本、参数,下次无法复现、无法对比。压测报告要把环境写清楚。

常见问题

Q1:-t 和 -c 怎么设?
-t 按压测机核数设(如 4 核设 4);-c 设成你要测的并发,且明显大于 -t。比如 -t4 -c100。想找极限可以阶梯加 -c,观察 QPS 拐点。

Q2:Requests/sec 忽高忽低正常吗?
小幅波动正常。若大幅波动,先查压测机是否成瓶颈、服务端是否有 GC 或缓存冷热问题、网络是否抖动。

Q3:Socket errors 有数字要紧吗?
要紧。connect 错误多为端口耗尽或服务端拒绝,timeout 多为服务端慢或网络差。先解决它,再看 QPS,否则数据不可信。

Q4:怎么测 HTTPS?
wrk 编译时带 OpenSSL 就支持,直接写 https:// 地址即可。注意 HTTPS 的握手开销会消耗更多 CPU。

Q5:wrk 能做分布式压测吗?
wrk 本身不内置分布式,需要自己用多台机器同时压,或用专门的分布式压测工具。单机不够用时,优先排查是不是压测机成瓶颈,再考虑多机。

Q6:为什么压测结果和线上监控对不上?
常见原因有几类:压测流量单一、没模拟真实请求分布;压测环境数据量、缓存状态和线上不同;压测机自己拖了后腿;线上还有别的业务共享资源。要尽量让压测环境贴近线上,并把压测报告里的环境信息写清楚,才能对比。

Q7:HTTPS 压测结果比 HTTP 低很多正常吗?
正常。TLS 握手加解密要消耗 CPU,连接建立阶段尤其明显。如果业务以短连接为主,HTTPS 开销更突出;用长连接(keep-alive)能摊薄握手成本,结果会更接近实际。

总结

  • wrk 是多线程事件驱动的 HTTP 压测工具,适合压高并发;RHEL 系一般需源码编译,Debian/Ubuntu 可尝试包安装。
  • 核心参数:-t 线程、-c 并发、-d 时长、--latency 看分布、-s 加载 Lua 脚本。
  • 结果重点:Requests/sec 是 QPS,Latency Distribution 看 P99,Socket errors 非零必须查。
  • 用 Lua 脚本发 POST 和随机参数,避免缓存干扰,让压测更贴近真实流量。
  • 小规模用 ab、正式用 wrk;永远把压测机与被测机分开,警惕压测客户端自己成为瓶颈。