
简介wrk-4.1.0-linux 是一款专为 Linux 环境设计的高性能 HTTP 基准测试工具面向后端开发、运维及性能测试人员用于高并发场景下 Web 服务器的压力测试与性能瓶颈分析尤其适合短连接、高并发的服务验证。压缩包采用 7z 格式整体约 168.72MB文件数量未单独标注内容以 C 语言源码、Lua 扩展脚本、编译配置及使用说明文档为主解压后可按文档命令完成编译、权限设置与环境准备。已有 586 人学习/下载。内容系统讲解了 wrk 的安装流程、常用参数如并发连接数、线程数、测试时长、自定义请求头及 Lua 脚本定制复杂请求场景并演示了通过输出中的总请求数、吞吐量、响应时间等指标评估服务性能同时对比 JMeter、ab 等工具的特性差异帮助读者结合场景选择合适工具快速定位高并发下的性能短板适合需要搭建轻量级压测环境的开发者参考。1. 先搞清楚 wrk 是什么为什么先用它做接口摸底wrk 是一个跑在 linux 命令行里的 HTTP 基准测试工具4.1.0 是它流传最广的一个版本号。它和 ab、siege 这类老牌工具最大的差别是几行命令、几十秒时间就能把一台机器的接口服务压到接近物理上限报告里直接给出吞吐、延迟分布和错误计数。对后端开发者、运维和性能测试工程师来说它是做接口容量摸底、性能回退排查、调优前后对比时最顺手的工具。这篇笔记不绕理论直接讲怎么在 linux 上装好 wrk 4.1.0、命令参数怎么设、输出怎么读以及我压测实践中踩过的几个坑。你以后看到「wrk 压测结果忽高忽低」先别急着换工具多数情况是环境和用法问题。2. wrk 4.1.0 编译安装源码方式与首个压测命令2.1 为什么我坚持源码编译版本与依赖的真相大多数 linux 发行版的软件源里都有 wrk 这个包一行命令就能装完。但我建议你编译 4.1.0 源码原因有两个一是软件源里的版本不受你控制有的发行版会冻结在某个旧版本行为和你查到的文档对不上二是 wrk 编译非常简单没有 configure、没有一堆依赖出问题一般也就是缺一个 OpenSSL 开发头文件自己编译反而最可控。wrk 4.1.0 运行时依赖 OpenSSL编译期需要 gcc、make 和 libssl-devCentOS 系叫 openssl-devel。它的源码里内置了 Lua 运行时所以你不需要单独装任何 Lua 环境这也是后面能用 Lua 脚本扩展压测场景的原因。下面这组命令在 Debian/Ubuntu 系上直接可跑。# 更新软件源把编译工具链一次装齐 sudo apt update sudo apt install -y build-essential libssl-dev git # 进入解压后的 wrk-4.1.0 源码目录 cd ~/src/wrk-4.1.0 # 直接编译-j$(nproc) 让 make 按 CPU 核数并行执行 make -j$(nproc) # 复制到 PATH 目录后续直接敲 wrk 就能用 sudo cp wrk /usr/local/bin/wrk # 验证版本 wrk --versionwrk 的 Makefile 不需要 configure 步骤make 之后目录里会出现一个名为 wrk 的二进制文件这一套流程和 linux 常用命令的安装习惯一致。cp 到 /usr/local/bin 是推荐做法如果你的 PATH 里没有这个目录改成 sudo cp wrk /usr/bin/wrk 即可。编译报错最常见的是找不到 openssl/ssl.h说明第二步的 libssl-dev 没装上在 CentOS 上把安装命令换成 yum install -y gcc make openssl-devel其余步骤完全一致。还有一个省事技巧wrk 编译出来是单二进制没有运行时动态库依赖我经常在一台机器上编译好直接把 wrk 文件同步到其他服务器使用省去每台机器都装工具链的时间。批量运维场景里这个做法比逐台编译更靠谱。2.2 跑通第一次压测最小命令拆解# 12 线程、200 并发连接、压 30 秒并打印延迟分布 wrk -t12 -c200 -d30s --latency http://127.0.0.1:8080/-t 是线程数-c 是并发连接总数-d 是持续时间--latency 要求在结束时打印延迟百分位分布。URL 必须是完整的 http:// 或 https:// 开头。注意 wrk 的并发模型里线程数和连接数是两个独立维度-c 200 表示总连接数由 12 个线程分摊平均每个线程维护 16 到 17 个连接。wrk 用非阻塞 I/O 加事件循环一个线程可以同时维护成百上千个长连接这一点和 ab 每个进程一个连接的模式完全不同。一次典型输出长这样Running 30s test http://127.0.0.1:8080/ 12 threads and 200 connections Thread Stats Avg Stdev Max /- Stdev Latency 45.23ms 12.89ms 231.45ms 62.34% Req/Sec 359.45 52.90 512.00 71.12% Latency Distribution 50% 41.78ms 75% 52.10ms 90% 63.02ms 99% 128.44ms 362280 requests in 30.08s, 48.65MB read Requests/sec: 12041.22 Transfer/sec: 1.62MB第一行是测试参数回顾Thread Stats 里 Latency 表示所有请求的延迟分布统计Req/Sec 表示每个线程平均每秒发出的请求数。Latency Distribution 是全部请求的延迟百分位最后两行才是总吞吐。这是一组典型的 200 连接压本地服务的数据Requests/sec 大约 1.2 万。2.3 线程模型与 epoll为什么 wrk 能压这么高wrk 每个线程各自创建一个 epoll 实例把连接注册进去用事件驱动方式收发请求。所有 socket 都是非阻塞的线程在事件循环里处理就绪事件空闲时不占 CPU。这个模型决定了三个实践结论一是线程数不需要特别大通常等于物理核数二是连接数可以远大于线程数因为连接只消耗文件描述符不消耗线程栈三是 keep-alive 长连接对压测结果影响很大wrk 默认复用连接发完请求不会立刻断开。ab 这类工具的并发模型是 fork 进程或单线程多连接连接一多上下文切换开销就上来了压测机自己先成为瓶颈。wrk 用事件驱动能把压测机的 CPU 更多花在真实请求收发上所以同样的机器配置wrk 能压出远高于 ab 的吞吐。这也是 linux 系统管理里常说的「压测先压压测机」问题的源头——工具选不对结果从根上就是错的。3. 读懂 wrk 输出三组必调参数与一个增速误区3.1 输出字段逐个拆解先看 Thread Stats 里的 Latency 行Avg 是所有请求的平均延迟Stdev 是标准差Max 是最大单次延迟/- Stdev 表示有多少比例的请求落在均值加减一个标准差内。这个百分比越高说明延迟越集中服务处理节奏越平稳。反过来如果这个数字很低说明延迟抖动严重服务端有间歇性排队或阻塞。Req/Sec 行统计的是每个线程每秒能发出的请求数注意它不是总 QPS总 QPS 要看最下面的 Requests/sec。Latency Distribution 里的 50/75/90/99 分位是判断毛刺的关键如果 99% 分位是 50msMax 却到了 800ms说明存在少量长尾请求这时候问题往往不在整体负载而在服务端的 GC、连接风暴或线程池排队。Socket errors 这行只在有错误时出现没有错误时不会显示。它分四类connect 是连接建立失败read 是读响应时被对端断开write 是请求写出失败timeout 是超过 --timeout 没收到响应。最后两行requests in 30.08s 是总请求数和总响应字节数Requests/sec 是整体 QPSTransfer/sec 是带宽吞吐。3.2 三组必调参数先看这张表参数作用典型取值备注-t线程数物理核数或核数×2不要远超核数-c并发连接数50 起步逐步加受 ulimit 限制-d压测时长短压 30s稳定性 5min支持 s/m/h 单位--timeout单请求超时默认 2 秒timeout 错误多时调大--latency打印延迟分布建议加上否则只有汇总统计-H自定义 Header按业务需要可重复传多次-sLua 脚本业务压测见第 5 章-c 连接数是最需要小心试出来的参数。我一般从 50 开始逐个翻倍到 200、500、1000每次盯住 Requests/sec 和 Latency 99% 分位的变化。连接数增加但 QPS 不再涨说明服务端已经到瓶颈再往上加连接只会拉高延迟。压测时长则要看目的做接口快筛 30 秒够用做容量评估建议至少 5 分钟让慢查询、GC、连接老化这些现象有时间暴露出来。提示wrk 4.1.0 没有固定 QPS 模式如果要做限速压测比如固定压 5000 QPS 而不是压到最大需要改用 wrk2 或自己用 Lua 控制请求间隔。这个边界很多人踩过先记住。3.3 线程数选多少一个常见的增速误区很多人以为 -t 越大越好实际不是。压 CPU 密集接口比如 JSON 序列化、加解密、模板渲染线程数超过物理核数后吞吐就不再上涨甚至回落压网络密集接口比如静态资源、网关转发可以按核数×2 起步。判断方法很简单先 nproc 看核数跑两轮对比。# 第一轮16 线程 wrk -t16 -c200 -d30s --latency http://127.0.0.1:8080/ # 第二轮32 线程 wrk -t32 -c200 -d30s --latency http://127.0.0.1:8080/对比两轮 Requests/sec取高者不要凭感觉定线程数。我见过不少新手把 -t 调到 64结果 QPS 只有 -t8 的一半原因就是线程调度开销超过了并发收益。wrk 线程数对总吞吐的影响是一条抛物线找到拐点比盲目堆线程重要得多。这个思路和 linux 运维故障案例里查「并发上不去」是同一套逻辑先确认资源边界再谈参数调优。4. wrk 压测避坑指南四个高频现象与根因4.1 连接数上不去ulimit 撞墙现象wrk -c 2000 一启动就报 Couldnt open socket 或 Too many open files。原因linux 单进程默认文件描述符上限是 10242000 个连接加上标准输入输出、epoll 实例等很快就撞上限。解决当前 shell 先执行 ulimit -n 1048576 再跑 wrk。注意 ulimit 只影响当前 shell 和它的子进程sudo 执行时会把资源限制重置为 root 默认值所以用了 sudo -i 之后要重新设置 ulimit。长期使用就改 /etc/security/limits.conf加上 * soft nofile 1048576 和 * hard nofile 1048576重新登录后生效。改完可以用 ulimit -n 验证。4.2 本机压本机结果忽高忽低现象同一命令连续跑三次Requests/sec 可能分别是 12000、9000、13500波动超过 30%被压服务端的 CPU 却始终不满。原因wrk 和被压服务在同一台机器上抢 CPUwrk 线程被调度打断节流抖动直接反映在数字上。另外 loopback 网卡不经过真实网络路径链路损耗为零压出来的数据只适合做同机对比不适合做容量预估。解决压测客户端和服务端拆到两台机器。如果一定要本机压用 taskset 把 wrk 绑到部分核服务端绑到另一部分核减少调度互相干扰# 绑定 wrk 到 1、3、5、7 四个核服务端跑在 0、2、4、6 上 taskset -c 1,3,5,7 wrk -t4 -c200 -d30s http://127.0.0.1:8080/taskset 的核编号要以 lscpu -e 输出的实际布局为准最好把两个进程分配到不同的物理核心上而不是超线程兄弟核。4.3 Socket errors 高分清是服务端还是压测机的问题现象报告出现 Socket errors: connect 120, read 45, timeout 30QPS 还在涨但业务方说服务端负载并不高。原因三类错误指向不同位置。connect 失败说明服务端 accept 队列满了接不过来read 错误是连接被对端主动断开比如 keep-alive 超时或接入层 resettimeout 是请求发出去后对端在超时时间内没回包服务端线程池排队或业务存在慢查询。解决先看哪类错误占大头再动手。connect 多调大服务端 listen backlogread 多查接入层和后端之间的连接超时配置timeout 多要查业务耗时而不是一味加 wrk 连接数。还有个经验wrk 的 timeout 默认 2 秒压业务接口时把 --timeout 调大到 10 秒或 30 秒能排除「服务端处理超过 2 秒」带来的噪音让结果更接近真实体验。4.4 线程数翻倍吞吐没动CPU 亲和与调度开销现象-t8 -c200 和 -t32 -c200 跑下来总 QPS 几乎一样有时 32 线程反而更低。原因CPU 核心数是物理边界wrk 线程数超过核数后事件循环线程互相抢核上下文切换开销吃掉收益。更隐蔽的是服务端如果配置了 CPU 绑定或 cgroup 限额压测机这边线程再多也压不上去。解决压测前用 nproc 和 lscpu 确认物理核数wrk 线程数设为物理核数。服务部署在容器里时还要确认容器 CPU 配额别拿超卖机器的数据当线上容量依据。压测结果是配置预算不是理论峰值这个认知能帮你省掉很多无效调参。5. 进阶用法用 Lua 脚本把 wrk 变成业务压测工具5.1 一段能直接用的 POST 脚本wrk 内置 Lua 运行时用 -s 指定脚本就能模拟真实业务不再只是打一个 GET 的静态页面。-- http_post.lua模拟带 JSON body 的 POST 请求 wrk.method POST wrk.headers[Content-Type] application/json function request() -- 每个请求的时间戳不同避免服务端缓存影响结果 local ts os.time() wrk.body string.format({user:tester,ts:%d}, ts) return wrk.format(POST, /api/submit, wrk.headers, wrk.body) endwrk -t4 -c100 -d60s -s http_post.lua http://127.0.0.1:8080wrk.method 放在脚本顶部表示全局请求方法request() 函数在每次请求前被调用返回的请求内容可以动态变化。wrk.format 的第一个参数是方法第二个参数是路径第三个是 headers第四个是 body。注意动态 body 的字符串拼接不要太重压测机自己是单线程 CPU 资源在 request() 里做复杂计算会让压测机先慢下来测出的数字就不是服务端的真实能力了。5.2 只统计 2xx 的响应response 与 done 组合-- status_check.lua按状态码统计请求结果 local total 0 local ok 0 function response(status, headers, body) total total 1 if status 200 then ok ok 1 end end function done(summary, latency, requests) local rate 0 if total 0 then rate ok / total * 100 end io.write(string.format(2xx rate: %.2f%% (%d/%d)\n, rate, ok, total)) endresponse() 每收到一个响应都会调用你可以在这里按状态码、响应头、响应体关键字做过滤统计done() 在压测结束时触发输出自定义结果。这个模板在验证限流、鉴权、灰度策略时特别有用把期望状态码改成 429 或 403就能快速确认策略是否按预期生效。我把这套脚本按 http_post.lua 和 status_check.lua 存成了模板每次接新接口先用最简命令跑基线再用 Lua 脚本补业务场景。压测这件事工具只是第一步真正花时间的是理解服务端瓶颈在哪。wrk 的好处是它足够透明输出简单、行为可预期能让你把精力花在分析上而不是学工具上。希望帮到你。本文还有配套的精品资源点击获取