彻底搞懂 wrk:HTTP 压测神器,用过的人都说好
大家好,我是小康。
前言
你有没有遇到过这种情况——
代码写完了,功能测试也过了,信心满满上线,结果一遇到真实流量,服务直接崩了?
或者老板问你:”这个接口能抗多少并发?”你支支吾吾说不出来……
这就是不做压测的代价。
今天就带大家认识一款 C/C++ 开发者必须掌握的压测神器——wrk。
一、什么是 wrk?
wrk 是一款高性能的 HTTP 压测工具,使用 C 语言编写,底层基于 epoll/kqueue 实现异步 I/O,用极少的线程就能产生巨大的并发压力。
相比 Apache Bench(ab)、JMeter 这些老牌工具,wrk 的优势非常明显:
|
|
|
|
|
|
|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
| wrk | C | 异步 I/O + 多线程 | ✅(Lua) | 极高 |
一句话总结:wrk 用 8 个线程,就能打出几万 QPS 的压力,是压测界的”轻量级格斗冠军”。
二、安装 wrk
Linux(Ubuntu/Debian)
sudo apt-get install build-essential libssl-dev git -ygit clone https://github.com/wg/wrk.gitcd wrkmakesudo cp wrk /usr/local/bin
Linux(CentOS/RHEL)
sudo yum groupinstall 'Development Tools'sudo yum install openssl-devel gitgit clone https://github.com/wg/wrk.gitcd wrkmakesudo cp wrk /usr/local/bin
macOS
brew install wrk
安装完成验证:
wrk --version# wrk 4.2.0 [epoll] Copyright (C) 2012 Will Glozer
看到版本号,说明安装成功 ✅
三、快速上手:第一个压测命令
wrk -t4 -c100 -d30s http://127.0.0.1:8080/api/hello
参数解释:
|
|
|
|---|---|
-t4 |
|
-c100 |
|
-d30s |
|
输出结果长这样:
Running 30s test @ http://127.0.0.1:8080/api/hello 4 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 2.34ms 1.12ms 45.23ms 89.45% Req/Sec 11.23k 1.45k 14.56k 72.34% 1344872 requests in 30.05s, 213.45MB readRequests/sec: 44754.23Transfer/sec: 7.10MB
怎么看这份报告?
-
Latency(延迟):平均 2.34ms,最大 45.23ms,说明大部分请求响应很快,偶尔有毛刺 -
Req/Sec:每秒每线程处理的请求数,乘以线程数就是总 QPS -
Requests/sec: 44754.23:这就是最终答案——这台服务器每秒能处理约 4.4 万次请求 -
Transfer/sec:每秒传输的数据量,用来评估带宽消耗
四、常用参数详解
wrk [选项] <URL>选项: -t, --threads 线程数(建议设置为 CPU 核心数的 2~4 倍) -c, --connections 并发连接数(连接数 >= 线程数) -d, --duration 压测持续时间(10s, 2m, 1h) -s, --script 加载 Lua 脚本 -H, --header 添加请求头,如 -H "Authorization: Bearer xxx" --latency 打印延迟分布(P50/P75/P90/P99) --timeout 请求超时时间(默认 2s)
关于线程数怎么设置?
经验法则:线程数 = CPU 逻辑核心数 连接数远大于线程数时,单线程会复用连接,充分利用 epoll 异步 I/O
# 查看 CPU 核心数nproc# 比如是 8 核,就设 -t8
五、实际常见用法大全
5.1 最简单的 GET 请求压测
wrk -t8 -c200 -d30s --latency http://127.0.0.1:8080/
加上 --latency 会输出延迟百分位分布:
Latency Distribution 50% 1.23ms 75% 2.45ms 90% 4.56ms 99% 12.34ms
P99 = 12.34ms 意味着 99% 的请求都在 12.34ms 内响应,这个指标在生产环境中非常重要。
5.2 带自定义请求头的压测
wrk -t4 -c100 -d30s \ -H "Authorization: Bearer your_token_here" \ -H "Content-Type: application/json" \ http://127.0.0.1:8080/api/user/info
5.3 POST 请求压测(Lua 脚本)
wrk 原生不支持直接指定 POST body,需要用 Lua 脚本。
创建文件 post.lua:
-- post.luawrk.method = "POST"wrk.body = '{"username":"test","password":"123456"}'wrk.headers["Content-Type"] = "application/json"
执行:
wrk -t4 -c100 -d30s -s post.lua http://127.0.0.1:8080/api/login
5.4 动态参数压测(每次请求参数不同)
真实场景下,你肯定不希望每次都发同一个请求——缓存可能会让结果失真。
创建 dynamic.lua:
-- dynamic.lualocal counter = 0request = function() counter = counter + 1localpath = "/api/item?id=" .. counterreturn wrk.format("GET", path)end
执行:
wrk -t4 -c100 -d30s -s dynamic.lua http://127.0.0.1:8080
每次请求的 id 都不一样,模拟真实随机流量,压测结果更有参考价值。
5.5 随机 User-Agent 模拟多端访问
-- random_ua.lualocal agents = {"Mozilla/5.0 (Windows NT 10.0; Win64; x64)","Mozilla/5.0 (iPhone; CPU iPhone OS 15_0)","curl/7.68.0","PostmanRuntime/7.29.0"}request = function()local ua = agents[math.random(#agents)] wrk.headers["User-Agent"] = uareturn wrk.format(nil, nil, nil, nil)end
5.6 先登录拿 Token,再压测需鉴权接口
这是生产中最常见的需求,分两步走:
Step 1:手动获取 token
curl -X POST http://127.0.0.1:8080/api/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"admin123"}'# 返回:{"token":"eyJhbGci..."}
Step 2:写 Lua 脚本带上 token
-- auth_test.luawrk.method = "GET"wrk.headers["Authorization"] = "Bearer eyJhbGci..."wrk.headers["Content-Type"] = "application/json"
wrk -t4 -c200 -d60s -s auth_test.lua http://127.0.0.1:8080/api/orders
5.7 压测结果统计(自定义 done 回调)
-- stats.lualocal requests_ok = 0local requests_err = 0response = function(status, headers, body)ifstatus == 200then requests_ok = requests_ok + 1else requests_err = requests_err + 1endenddone = function(summary, latency, requests)print("---------- 自定义统计 ----------")print(string.format("成功请求: %d", requests_ok))print(string.format("失败请求: %d", requests_err))print(string.format("P50延迟: %.2fms", latency:percentile(50) / 1000))print(string.format("P99延迟: %.2fms", latency:percentile(99) / 1000))print("--------------------------------")end
5.8 多接口轮询压测(模拟混合流量)
-- multi_path.lualocal paths = {"/api/user/list","/api/order/query","/api/product/detail?id=1","/health"}request = function()localpath = paths[math.random(#paths)]return wrk.format("GET", path)end
模拟真实生产环境下多个接口同时被访问的场景,比单接口压测更接近实际情况。
5.9 阶梯压测脚本(手动模拟流量爬升)
wrk 本身不支持阶梯并发,但可以用 shell 脚本模拟:
#!/bin/bash# step_load.shURL="http://127.0.0.1:8080/api/hello"for conn in 10 50 100 200 500 1000; doecho">>> 并发连接数: $conn" wrk -t4 -c$conn -d15s --latency $URL | grep -E "Req|Latency|requests"echo"" sleep 3done
这样就能看出服务在不同并发下的性能曲线,快速找到性能拐点。
六、压测报告怎么分析?
光会跑还不够,更重要的是看懂数据。
Thread Stats Avg Stdev Max +/- Stdev Latency 2.34ms 5.12ms 245.23ms 95.67% Req/Sec 5.23k 1.23k 8.45k 68.34%Socket errors: connect 0, read 12, write 0, timeout 3Non-2xx or 3xx responses: 45
几个关键信号:
🔴 Socket errors 不为零 → 说明服务扛不住了,出现了连接拒绝、读写失败或超时
🔴 Non-2xx or 3xx responses 有值 → 服务返回了错误,要检查服务端日志
🟡 Latency 的 Stdev 很大 → 延迟波动剧烈,服务不稳定,可能存在 GC、锁竞争等问题
🟡 Max 延迟远大于 Avg → 存在长尾延迟,说明某些请求会被”卡住”
🟢 Stdev 小、P99 接近 P50 → 服务稳定,延迟可预期,是优秀服务的表现
七、wrk 的局限性
用了这么久 wrk,它的坑也得说清楚:
-
只支持 HTTP/HTTPS,不支持 TCP、WebSocket、Unix Domain Socket 等协议 -
不支持 HTTP/2(官方维护较少) -
不支持 Windows(只能在 Linux/macOS 上跑) -
不支持分布式压测,单机并发上限受限于本机资源 -
Lua 脚本功能有限,复杂场景编写麻烦 -
没有图形化界面,结果需要自己解读
八、进阶推荐:wrk 不够用了怎么办?
说到 wrk 的局限,忍不住给大家推荐一个更强的工具——
hbench:这是我自己用 C++ 从零实现的一款高性能 HTTP 压测工具。
为什么要造这个轮子?因为在实际项目开发中,我们经常遇到这些场景:
-
要压测基于 Unix Domain Socket 的本地 IPC 服务 -
要压测裸 TCP 协议的自定义服务 -
要在同一个工具里统一压测 HTTP 和非 HTTP 服务
wrk 统统搞不定,而 hbench 全部支持。hbench课程链接:wrk 压不了 TCP?我用 2000 行纯 C 手撸了一个能压三种协议的压测工具
对于做 C++ 后端、网络编程的同学来说,hbench 是比 wrk 更全能的压测工具,而且源码比wrk更容易学习,可以直接学习其中的 epoll 异步模型、连接池设计、统计模块实现,一份代码,学到工业级工程经验。
九、总结
今天我们系统学习了 wrk 的用法:
-
✅ wrk 基本原理与安装 -
✅ 核心参数详解 -
✅ GET/POST/带 Token/随机参数等常见场景 -
✅ Lua 脚本进阶用法 -
✅ 压测报告解读方法 -
✅ wrk 局限性与替代方案
压测这件事,能帮你在上线前把问题暴露出来,而不是等到用户投诉才发现。 建议每个后端项目在上线前都跑一遍压测,把 QPS 上限、P99 延迟、错误率这三个指标摸清楚。
附:课程推荐
如果你读完这篇还觉得 C、C++、Linux 有些陌生,别急——我也开设了这三门入门课程,从零带你打好地基,快速上手项目实战:
-
C 语言快速入门 :大一啃完谭浩强的书,还是不会写代码?我花1个月做了套’12天速成’的C语言课 -
C++ 快速入门 :12天,从C++小白到独立做项目!我把3年踩坑经验浓缩成了这门课 -
Linux 编程快速入门 :为什么你学了半年 Linux 编程,还是写不出一个像样的程序?
感兴趣可以了解一下。
如果你已经有一定基础,想冲击更高的天花板,那下面这些工业级 C++ 项目正是为你准备的:
C++ 项目课程列表:
|
|
|
|---|---|
| 线程池 |
|
| 高性能日志库 MiniSpdlog |
|
| 高性能内存池 |
|
| 多线程下载工具 |
|
| MySQL 连接池 |
|
| 内存泄漏检测器 |
|
| ReactorX |
|
| 无锁栈
|
|
| 工业级智能指针(shared_ptr) |
|
| 高性能网络库 NetCore |
|
| 高性能异步日志库 ZephyrLog |
|
| 死锁检测工具 |
|
| 高性能 HTTP 服务器 |
|
| 协程库 CoroForge |
|
| 高性能 HTTP 压测工具 |
|
| Redis 核心模块实战 |
|
每一个项目都是工业级实现,代码量从几百行到几千行不等,覆盖高并发、网络编程、内存管理、无锁数据结构等核心方向。
👉 详情点击 C++ 项目合集课程链接:为什么同样是”学过C++”,有人面试碾压,有人开口就怂?差距在这18个C++硬核项目
觉得有用的话,点赞、推荐、转发给你的同事,让更多人在上线前把服务压垮在测试环境里,而不是生产环境 😄
有问题欢迎在评论区留言,我都会回复。
夜雨聆风