4、wrk实战:wrk安装、基本参数(-t, -c, -d)、压测一个HTTP服务并解读结果

好,咱们进入实战环节。前面聊了那么多理论,现在该动手了。这一章我带你玩转 wrk,一个轻量级的 HTTP 压测工具。说实话,我用了这么多年压测工具,wrk 是我个人最常用的之一——因为它够快、够简单,几行命令就能把服务的底裤扒干净。

4.1 wrk 安装:别踩这些坑

先说说安装。wrk 的安装其实很简单,但我在项目中遇到过几次因为环境问题折腾半天的情况。嗯,这里要注意几个点。

Linux 环境安装

# 从源码编译安装(推荐)
git clone https://github.com/wg/wrk.git
cd wrk
make

# 安装到系统路径
sudo cp wrk /usr/local/bin/

# 验证安装
wrk --version

你可能会问:为什么不用 apt-get 直接装?我建议你尽量用源码编译。为什么?因为系统源里的 wrk 版本往往比较老,有些新特性不支持。我记得有一次在 CentOS 7 上用 yum 安装,结果版本是 4.0.1,连 HTTP/2 都不支持,白忙活半天。

⚠️ 注意: wrk 依赖 OpenSSL 和 LuaJIT。如果你在编译时报错,先检查这两个库有没有装。命令:sudo apt-get install libssl-dev luajit(Ubuntu)或 sudo yum install openssl-devel luajit(CentOS)。

macOS 环境安装

brew install wrk

macOS 用户就简单了,Homebrew 一把梭。不过要注意,M1/M2 芯片的 Mac 可能会遇到一些兼容性问题,建议用 Rosetta 2 模式运行。

4.2 核心参数:-t, -c, -d 到底怎么用?

wrk 的参数不多,但每个都很关键。说白了,你只要搞懂这三个参数,就能应付 90% 的场景。

参数 全称 含义 我的建议
-t threads 压测线程数 一般设为 CPU 核心数的 2-4 倍
-c connections 保持的连接数 从 100 开始,逐步增加
-d duration 压测持续时间 至少 30 秒,推荐 60 秒

-t 线程数:你想想看,线程数不是越多越好。我见过有人一上来就开 64 个线程,结果 CPU 上下文切换开销比压测本身还大。我个人习惯是:先看服务器 CPU 核心数,比如 8 核,我就设 -t 16。为什么?因为 wrk 的线程是 I/O 密集型的,多开一点能充分利用 CPU。

-c 连接数:这个参数模拟的是并发连接数。注意,它不等于 QPS。我曾经犯过一个错误:以为 -c 越大 QPS 越高。结果发现当连接数超过某个阈值后,QPS 反而下降了——因为连接管理本身也有开销。建议从 -c 100 开始,每次翻倍,直到找到拐点。

-d 持续时间:压测时间太短没有意义。为什么?因为 JVM 有预热、连接池有初始化、GC 有抖动。我一般至少跑 60 秒,前 10 秒的数据直接丢弃不看。你想想看,如果只跑 10 秒,可能刚好碰到一次 Full GC,结果就失真了。

4.3 实战:压测一个 HTTP 服务

好,理论说完了,咱们直接上手。假设我要压测一个本地的 Spring Boot 服务,端口是 8080,接口是 /api/hello。

# 基础压测命令
wrk -t 12 -c 400 -d 30s http://localhost:8080/api/hello

这条命令的意思是:用 12 个线程,保持 400 个并发连接,持续压测 30 秒。跑完之后,你会看到类似这样的输出:

Running 30s test @ http://localhost:8080/api/hello
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    45.67ms   12.34ms  256.78ms   75.23%
    Req/Sec    723.45    89.12     1.02k     68.90%
  259842 requests in 30.00s, 34.56MB read
  Socket errors: connect 0, read 0, write 0, timeout 0
Requests/sec:   8661.40
Transfer/sec:      1.15MB

这个结果怎么看?我带你逐行解读。

4.4 结果解读:别只看 QPS

第一行:测试概要

告诉你跑了多久、压的哪个地址、用了多少线程和连接。这里有个小细节:如果压测时间比设定的短,说明服务扛不住提前挂了。我曾经遇到过压了 10 秒服务就 OOM 的情况,结果直接报错退出。

Thread Stats 部分:延迟分布

  • Latency Avg:平均延迟 45.67ms。这个值越低越好。
  • Latency Stdev:标准差 12.34ms。如果这个值很大,说明延迟波动厉害,服务不稳定。
  • Latency Max:最大延迟 256.78ms。这个值很关键——如果最大延迟是平均延迟的 5 倍以上,说明有长尾请求。
  • +/- Stdev:75.23% 的请求在标准差范围内。这个比例越高,说明延迟越集中。
💡 我的经验: 看延迟不要只看平均值。我见过一个服务平均延迟 50ms,但 P99 延迟到了 2 秒。这种服务在线上就是定时炸弹。建议用 --latency 参数看百分位延迟。

Req/Sec 部分:吞吐量

  • Avg:每个线程每秒处理 723.45 个请求。
  • Max:峰值达到 1.02k。这个值可以帮你判断服务的极限在哪里。

总请求数和数据量

30 秒内处理了 259842 个请求,读取了 34.56MB 数据。这里要注意:如果 read 的数据量远小于预期,说明响应体可能被截断了或者服务返回了错误。

Socket errors

这个部分很重要。如果 connect 或 timeout 不为 0,说明服务端连接池满了或者处理不过来。我遇到过最夸张的一次,timeout 达到了 5000+,一看日志,数据库连接池爆了。

Requests/sec 和 Transfer/sec

最终的两个核心指标:QPS 是 8661.40,吞吐量是 1.15MB/s。这两个值就是你的服务在当前配置下的性能基准。

4.5 进阶技巧:加参数看更多细节

基础用法学会了,我再分享几个我常用的参数组合。

# 看延迟分布(推荐)
wrk -t 12 -c 400 -d 30s --latency http://localhost:8080/api/hello

# 输出结果到文件
wrk -t 12 -c 400 -d 30s --latency http://localhost:8080/api/hello > result.txt

# 使用 Lua 脚本模拟复杂场景
wrk -t 12 -c 400 -d 30s --script=post.lua http://localhost:8080/api/submit

--latency 参数会额外输出延迟的百分位数据,比如 P50、P75、P90、P99。我个人习惯是:P99 延迟不能超过平均延迟的 3 倍,否则就要优化。

🎯 小技巧: 如果你压测的是 POST 接口,可以写一个 Lua 脚本。比如模拟登录场景,每次请求带不同的用户名和密码。wrk 的 Lua 支持虽然简单,但应付 80% 的场景足够了。

4.6 避坑指南

最后,我总结几个实战中容易踩的坑。

  • 不要在本机压本机:我曾经犯过这个错,结果压出来的 QPS 高得离谱,以为是服务优化得好,后来发现是网络延迟为 0 导致的假象。建议至少用两台机器,或者用 Docker 隔离。
  • 注意 ulimit 限制:Linux 默认的文件描述符限制是 1024,如果你开 400 个连接,每个连接可能占用多个 fd,很容易超限。记得先执行 ulimit -n 65535。
  • 压测时间别太短:至少 30 秒,推荐 60 秒。我见过有人压 5 秒就下结论,结果服务刚启动还在预热,数据完全不可信。
  • 关注错误率:如果 QPS 很高但错误率也高,那这个 QPS 没有意义。我一般要求错误率低于 0.1%。

好了,wrk 的实战就讲到这里。你拿着这些参数去压一下自己的服务,看看结果是不是符合预期。记住,压测不是为了得到一个好看的数字,而是为了找到服务的瓶颈在哪里。

📊 核心逻辑图:wrk 压测流程 1. 安装 wrk 2. 配置参数 -t 线程数 -c 连接数 -d 时长 3. 执行压测 4. 解读结果 延迟分布 | QPS | 错误率 | 吞吐量 5. 定位瓶颈 & 优化 迭代优化
可可精品资料库