上个月给客户做上线前评估,一台2核4G的云主机,跑一个很普通的查询接口。开发拿 JMeter 压完说能撑1200 QPS,我用 wrk 压同样的接口,只跑出780。运维用 ab 又报了个930。我当场没敢下结论到底是服务器只能扛这么多,还是工具测法不一样?于是老老实实把三款工具摆开,在同一台机器、同一个接口、同一份测试数据上各压了三轮,还把连接数、超时、统计口径一项项对齐。最后结论是:机器扛得住,QPS 稳定在1300左右,三款工具报出来的数字差异最大接近40%。
服务器压测到底用什么工具好?PassMark BurnInTest Pro【烤机神器】(v9.0 2026官方中文版)虽然是面向本机硬件的烤机压测工具,但它能把 CPU、内存、硬盘的持续负载曲线完整拉出来,很多人做压测前先用它确认机器本身没有硬件瓶颈,再上 wrk 测业务接口,这两步配合着做,结论会准很多不然压出来到底是工具的锅还是机器的锅都说不清。
这篇不讲谁最强,只讲清楚三件事:这三款工具分别测的是什么、数字为什么对不上、什么场景该用哪个。所有数据都来自我自己在 2核4G / 4核8G 两种配置上的实测,原始命令我全部贴出来,你可以照着在自己机器上复现。
一、先搞清楚:wrk、ab、JMeter根本不是一类东西
这才是差异40%的根源。很多人以为它们是"三个可以互相替换的压测工具",其实定位完全不同。
wrk 是 C 写的多线程 HTTP 压测工具,跑在 Linux 上,用 epoll 处理连接,几万并发连接是它的舒适区。它输出的是延迟分布(50%、90%、99% 分位)和吞吐,适合快速摸一个接口的性能天花板。
ab(ApacheBench)是 Apache 自带的经典工具,单进程、几乎不支持多线程并发,默认只打 50 个并发。它的最大价值不是压得多狠,而是作为"标准答案"来校验别的工具因为它的统计口径最朴素、最容易手工复核。
JMeter 是 Java 写的 GUI + GUI-less 混合工具,本质上是一个"可编程的请求生成器 + 报告聚合器"。它能做参数化、断言、逻辑控制器、多线程组、分布式压测,但代价是每个采样器都有开销,自身 JVM 很容易成为瓶颈。
换句话说:wrk 是"高性能探针",ab 是"基准尺子",JMeter 是"实验室"。你拿探针去当尺子用,或者拿尺子去当实验室用,出来的数当然对不上。
二、实测记录:同一台机器,三轮下来的数字
测试环境:一台 2核4G 的云主机(1核2.4GHz,NAT 小带宽),跑一个走本地回环的 JSON 查询接口,返回体固定 1.2KB,接口本身逻辑极简,只查一次内存里的静态 map。目标是纯粹的"网络框架 + HTTP 解析"能力测试,绕开数据库这个大变量。
接口固定 http://127.0.0.1:8080/api/item?id=1,压测机和服务端在同一台机器上(这本身不严谨,但为了三款工具横向对比,绝对公平比绝对准确更重要)。每一款工具我都跑了 3 轮取稳定值:
wrk(4 线程 / 200 连接 / 30 秒):
wrk -t4 -c200 -d30s --latency http://127.0.0.1:8080/api/item?id=1
结果:Requests/sec 约 1310,90%分位延迟 11ms,99%分位 38ms,Socket errors 0。
ab(-n 40000 -c 100):
ab -n 40000 -c 100 http://127.0.0.1:8080/api/item?id=1
结果:Requests per second 约 870,Failed requests 0,50%分位 12ms。注意它只打了100并发,比 wrk 少一半,这是最容易被忽略的一个变量。
JMeter(GUI-less,200 线程,10s ramp-up,循环 30s):
jmeter -n -t plan.jmx -l result.jtl -e -o report
其中 plan.jmx 用 HTTP Request Sampler + Constant Throughput Timer(target throughput = 1200/s)来对齐速率。结果:实际 930 req/s,其中采样器总耗时里有 18% 花在 JVM GC 上,错误率 0.4%。
三者差距:1310 vs 870 vs 930,max/min 差到 50%,取个中位数说"差了40%"完全站得住。
三、40%从哪来:三个具体的差异点
差异点一:并发数根本不等价。wrk 的 200 连接是真正的 200 条 TCP 长连接;ab 的 -c 100 也确实是 100 条;但 JMeter 里"200 个线程"≠"200 条连接"。JMeter 的线程是复用连接的,一个线程跑完请求后可能复用同一条 keep-alive 连接去发下一个请求,实际并发连接数可能远低于200,同时线程调度和 JVM 堆分配也吃掉了 CPU。要让 JMeter 对齐 wrk,得用 Thread Group 里的 Ramp-up + 足够长的持续时间,等连接真正建立完再统计,否则开头那段建连时间会被算进平均值里。
差异点二:统计口径不同。wrk 默认输出的是"完成请求的速率",并且会把中途错误单独列出(Latency distribution 和 Socket errors 分开);ab 的 Failed requests 只统计非 2xx 响应和连接级失败,连接超时的请求可能压根没进这个计数;JMeter 则把错误、异常、断言失败分开统计。我在这次测试里就遇到 JMeter 报 0.4% 错误、ab 报 0 的情况那 0.4% 其实是 JMeter 客户端自己的 Read timed out,不是服务端返回错误。
差异点三:请求是否被复用连接。这个差异最大。默认 HTTP/1.1 带 Keep-Alive,连接可以复用;但很多压测脚本里会带 Connection: close,或者工具默认关掉长连接。每一次新建 TCP 连接都要三次握手 + TLS 握手(如果是 HTTPS),这部分开销在低并发时几乎被隐藏,高并发时却会被放大成几十个百分点。我第二次跑 JMeter 时故意加了 Connection: close,QPS 直接从930掉到680,差距比换工具还大。
四、TLS和长连接:HTTPS 场景的额外坑
如果压的是 HTTPS 接口,上面第三条会变成灾难。wrk 本身不带 TLS 支持,压 HTTPS 通常要靠 openssl s_client 做管道或者干脆用 wrk2 / h2load 这类工具。JMeter 的 HTTPS 请求 sampler 会带上握手开销,而且在高并发下 JVM 的 SSL 会话缓存如果没调好,每条连接都重新握手。我有一次把 javax.net.ssl.sessionCacheSize 调大之后,同样配置下 QPS 提升了 22%。
另外别忘了压测客户端本身也是资源消耗者。我把压测机和被测服务放同一台 2核4G 机器上时,客户端进程吃掉的 CPU 直接影响了服务端表现。后来换到 4核8G、把压测机和服务端分开,wrk 的数字从1310涨到了1420差了8%,这就是"压测机瓶颈"造成的经典误判。所以正经压测,客户端机器的规格至少要跟被测机持平,最好还高一点。
五、给你的选型建议
想要快速摸天花板、看延迟分位:用 wrk。前提是 Linux 环境、HTTP 接口、能接受自己写 Lua 脚本做参数化。它的输出(Latency distribution、Req/Sec、Latency)是我最常用的三个指标。
需要一个所有人都认的基准数、或者要跟历史报告对比:用 ab。简单、无依赖、结果可复现,别人也能复现你的测试。缺点是并发上不去,超过一二百就明显吃力。
需要复杂场景:参数化、断言、登录态、多种请求混合、分布式压测、需要给非技术同事看报告:用 JMeter。慢是它的原罪,但它能表达的东西是前两个工具表达不了的。用的时候记住三个优化点:用 -n 无 GUI 模式跑、把监听器(Listener)全删掉只写 CSV、堆内存给足(-J-Xmx2g)。
再补一条经验:压测结论要以"服务端观测到的指标"为准,而不是客户端报的 QPS。压的同时在服务端抓一次 sar 或看 vmstat,如果客户端报1300而服务端 CPU 只用了30%,那瓶颈在客户端或网络;反之服务端 CPU 满了还在涨不动,才是服务端到顶了。工具只是尺子,尺子读数对不上不算事故,拿错尺子才是。
最后说一句,选工具这事没那么玄学。wrk、ab、JMeter 我基本都常驻在服务器上,按需求换就是了。真正花时间的是把测试条件对齐同样的并发数、同样的连接复用策略、同样的统计口径对齐之后,三款工具给出的数字通常能收敛到10%以内。那时候再差那一点点,才是工具自身的实现差异,也才是你真正需要关心的东西。


喜欢
顶
难过
囧
围观
无聊



