压测工具选型:JMeter、wrk、Locust、GoReplay 对比与选型策略
做压测这么多年,我经常被问到同一个问题:「到底该用哪个工具?」
说实话,没有银弹。每个工具都有自己的脾气。选错了,你可能会在压测过程中被工具本身坑一把。我见过有人用 JMeter 压 10 万并发,结果 JMeter 自己先挂了。也见过有人用 wrk 测 HTTP 接口,测到一半发现没法做参数化,整个脚本重写。
所以这一章,咱们把四个主流工具掰开揉碎聊一聊。你听完就知道,什么场景该拿什么工具。
核心观点:选工具不是选「最好的」,而是选「最不坏的」。你的业务场景、团队技术栈、压测目标,这三者决定了最终答案。
一、四款工具的核心定位
先给个全景图。我习惯用一张表来快速对齐认知:
| 工具 | 语言/协议 | 并发模型 | 核心优势 | 典型场景 |
|---|---|---|---|---|
| JMeter | Java / 多协议 | 线程池 | 生态丰富,GUI 调试方便 | 复杂业务链路、多协议混合 |
| wrk | C / HTTP | 事件驱动 + 多线程 | 单机性能极高,延迟低 | 单接口吞吐量摸底、快速验证 |
| Locust | Python / HTTP | 协程 (gevent) | 脚本灵活,分布式原生 | 自定义行为、动态参数、持续集成 |
| GoReplay | Go / HTTP | 流量复制 | 真实流量回放,零侵入 | 线上流量录制、回归压测 |
嗯,这张表你大概扫一眼就行。下面咱们一个一个拆。
二、JMeter:老牌劲旅,但别让它成为瓶颈
JMeter 是我入行时用的第一个压测工具。说实话,它的 GUI 在调试阶段确实好用——拖拖拽拽就能配出一个请求,参数化、断言、监听器一应俱全。
但你要注意一个坑:JMeter 本身也是 Java 应用。它的线程模型是每个虚拟用户对应一个 Java 线程。当并发数超过 1000 时,JMeter 的 GC 开销和线程切换成本会急剧上升。我曾经在项目中用 JMeter 压 3000 并发,结果 JMeter 自己 CPU 跑满了,目标服务器反而很闲。
避坑指南:JMeter 做高并发压测时,一定要用命令行模式(jmeter -n -t),关掉 GUI 和监听器。如果单机扛不住,就用分布式模式。但分布式又引入同步和聚合的问题——嗯,这是另一个坑。
JMeter 的强项在于:
- 多协议支持:HTTP、JDBC、JMS、FTP、gRPC(通过插件)都能测
- 断言和提取器丰富:JSON Extractor、正则提取器、XPath 断言,调试链路很方便
- 社区插件多:像 PerfMon、jp@gc 系列,扩展性不错
但它的短板也很明显:脚本维护成本高。一个复杂的业务链路,JMeter 的 GUI 文件(.jmx)动辄几千行 XML,版本 diff 基本没法看。我后来更倾向于用代码写压测脚本,而不是拖拽。
三、wrk:轻量级利器,适合快速摸底
wrk 是我做「快速验证」时的首选。它用 C 写的,基于事件驱动 + 多线程,单机就能压出很高的吞吐量。
举个例子,我想知道一个接口的极限 QPS 是多少。用 JMeter 可能要配半天,用 wrk 一行命令就够了:
wrk -t12 -c400 -d30s --latency http://target/api/health
这条命令的意思是:12 个线程,400 个连接,持续 30 秒,输出延迟分布。跑完就能看到 P50、P75、P99 和吞吐量。
但 wrk 的局限性也很明显:
- 只支持 HTTP:不能测数据库、消息队列
- 脚本能力弱:虽然支持 Lua 扩展,但写复杂逻辑很痛苦
- 无分布式能力:单机压不动时,你得自己搭集群
我的习惯:先用 wrk 快速摸一下接口的「天花板」,知道大概能扛多少 QPS。然后再用 JMeter 或 Locust 去压复杂链路。这样效率最高。
四、Locust:Python 工程师的压测利器
Locust 是我个人比较偏爱的工具。原因很简单:脚本就是 Python 代码。你可以用 for 循环、if 判断、随机数、外部数据源,想怎么玩就怎么玩。
看一个典型的 Locust 脚本:
from locust import HttpUser, task, between
class WebsiteUser(HttpUser):
wait_time = between(1, 5)
@task(3)
def view_item(self):
self.client.get("/item?id=1001")
@task(1)
def add_to_cart(self):
self.client.post("/cart", json={"item_id": 1001})
你看,权重、等待时间、请求方法,全在代码里。想加个随机参数?写一行 random.choice() 就行。
Locust 的另一个优势是原生分布式。启动一个 master 和多个 worker,用 --web 参数就能在浏览器里看到实时 QPS 和响应时间。我在项目中用它压过 5 万并发,配合 8 台 worker 机器,效果不错。
但 Locust 也有坑:
- 协程模型有局限:gevent 的 monkey patch 有时会和第三方库冲突
- 报告功能弱:没有 JMeter 那么丰富的图表,需要自己对接 InfluxDB + Grafana
- 协议支持有限:原生只支持 HTTP,其他协议需要自己写 client
一句话总结:如果你的团队以 Python 为主,压测场景需要灵活定制,Locust 是最佳选择。但如果你需要开箱即用的报告和断言,JMeter 更省事。
五、GoReplay:线上流量复制,零侵入压测
GoReplay 是个「异类」。它不生成虚拟用户,而是录制线上真实流量,然后回放到压测环境。
我为什么说它重要?因为很多时候,我们自己写的压测脚本和真实用户行为有偏差。比如用户点击的路径、参数分布、请求间隔,脚本很难完全模拟。GoReplay 直接拿线上流量来压,真实度最高。
用法也很简单:
# 录制流量
gor --input-raw :80 --output-file requests.gor
# 回放流量
gor --input-file requests.gor --output-http "http://staging:8080"
但 GoReplay 不是万能的:
- 只能回放 HTTP:不支持 TCP、gRPC 等协议
- 无法控制并发:回放速度取决于录制时的流量密度
- 数据脱敏麻烦:线上流量可能包含敏感信息,需要做过滤或替换
我曾经踩过的坑:有一次直接用线上流量回放,没注意里面有个写操作接口。结果压测环境的数据被改得乱七八糟。后来我学乖了,回放前一定先过滤掉写请求,或者把目标环境指向只读库。
六、选型决策框架
说了这么多,到底怎么选?我画了一张决策流程图,你跟着走一遍就知道了:
你看,决策路径其实很清晰:
- 有线上流量? → 优先用 GoReplay,真实度最高
- 单接口快速摸底? → wrk,一行命令出结果
- 复杂链路 + Java 团队? → JMeter,生态最成熟
- 复杂链路 + Python 团队? → Locust,灵活定制
我的实战组合:在大多数项目中,我会同时用 wrk 和 Locust。wrk 用来做「快速健康检查」,每次代码变更后跑一遍,确保性能没回退。Locust 用来做「全链路压测」,模拟真实用户行为,压出系统的瓶颈点。两个工具互补,基本覆盖了 80% 的场景。
七、选型避坑清单
最后,我把自己踩过的坑整理成一份清单。你选型时对照着看,能省不少时间:
- 别让压测工具成为瓶颈:JMeter 单机超过 2000 并发时,优先考虑分布式或换工具
- wrk 不适合复杂场景:需要登录态、参数化、断言时,别硬用 wrk 的 Lua
- Locust 注意 gevent 兼容性:如果被测服务用了某些 C 扩展库,可能和 monkey patch 冲突
- GoReplay 一定要做流量过滤:写操作、敏感数据、重复请求,都得提前处理
- 不要迷信「真实流量」:GoReplay 回放的是历史流量,不代表当前系统状态。压测结果仅供参考