压测工具选型: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 还是 Python? Java JMeter Python Locust 提示:以上决策为通用建议。实际项目中,经常需要组合使用多个工具。 例如:wrk 快速摸底 → Locust 压复杂链路 → GoReplay 做线上验证

你看,决策路径其实很清晰:

  1. 有线上流量? → 优先用 GoReplay,真实度最高
  2. 单接口快速摸底? → wrk,一行命令出结果
  3. 复杂链路 + Java 团队? → JMeter,生态最成熟
  4. 复杂链路 + Python 团队? → Locust,灵活定制

我的实战组合:在大多数项目中,我会同时用 wrk 和 Locust。wrk 用来做「快速健康检查」,每次代码变更后跑一遍,确保性能没回退。Locust 用来做「全链路压测」,模拟真实用户行为,压出系统的瓶颈点。两个工具互补,基本覆盖了 80% 的场景。

七、选型避坑清单

最后,我把自己踩过的坑整理成一份清单。你选型时对照着看,能省不少时间:

  • 别让压测工具成为瓶颈:JMeter 单机超过 2000 并发时,优先考虑分布式或换工具
  • wrk 不适合复杂场景:需要登录态、参数化、断言时,别硬用 wrk 的 Lua
  • Locust 注意 gevent 兼容性:如果被测服务用了某些 C 扩展库,可能和 monkey patch 冲突
  • GoReplay 一定要做流量过滤:写操作、敏感数据、重复请求,都得提前处理
  • 不要迷信「真实流量」:GoReplay 回放的是历史流量,不代表当前系统状态。压测结果仅供参考