第三章:压测工具选型——选对工具,事半功倍

做性能压测这么多年,我经常被问到:“到底该用哪个工具?”说实话,没有完美的工具,只有最适合你场景的。今天我就把 JMeter、Locust、wrk、ab、Gatling 这几款主流工具掰开揉碎讲清楚。

核心观点:工具选型取决于三个维度——业务场景、技术栈、团队能力。没有银弹,只有权衡。

3.1 五款主流工具速览

先上一张对比表,让你对它们有个整体印象。

工具 协议支持 语言/脚本 并发模型 分布式 学习成本
JMeter HTTP、JDBC、JMS、FTP 等 GUI 配置 + Groovy/Java 线程池 支持 中等
Locust HTTP、HTTP/2、WebSocket Python 协程(gevent) 支持 低
wrk HTTP/1.1 C + Lua 多线程 + epoll 不支持 高
ab HTTP/1.0、HTTP/1.1 命令行参数 单/多进程 不支持 极低
Gatling HTTP、WebSocket、SSE Scala(基于 DSL) 异步非阻塞(Akka) 支持 较高

这张表的信息量很大。我一个个拆开讲。

3.2 JMeter —— 老牌全能王

说到压测,JMeter 是绕不开的。它就像瑞士军刀,什么都能干。HTTP、数据库、消息队列,甚至自定义协议,它都能搞定。

我个人习惯用它来做复杂的业务场景编排。比如一个电商下单流程,需要先登录、加购物车、提交订单、支付,每一步之间还有参数依赖。用 JMeter 的 GUI 拖拖拽拽就能配出来。

避坑提醒:我曾经在压测一个高并发接口时,发现 JMeter 本身成了瓶颈。后来把 GUI 模式换成非 GUI 模式跑,压测机从 4 核 8G 换成 8 核 16G,问题解决了。

跑非 GUI 模式的命令很简单:

jmeter -n -t test.jmx -l result.jtl -e -o report/

参数说明:-n 非 GUI 模式,-t 指定脚本,-l 保存原始结果,-e 自动生成 HTML 报告。

3.3 Locust —— Pythoner 的菜

如果你团队全是 Python 开发者,那 Locust 会是你的首选。它用协程代替线程,单机就能模拟成千上万的并发用户。

写个简单的压测脚本:

from locust import HttpUser, task, between

class WebsiteUser(HttpUser):
    wait_time = between(1, 5)

    @task(3)
    def index(self):
        self.client.get("/")

    @task(1)
    def search(self):
        self.client.post("/search", json={"q": "test"})

@task(3) 的意思是访问首页的频率是搜索的 3 倍。这种用代码定义用户行为的方式,非常灵活。

我记得有一次要模拟 5000 个用户同时登录,用 JMeter 跑了 3 台从机才撑住,换成 Locust 后一台机器就够了。原因很简单——协程的开销远小于线程。

3.4 wrk —— 纯性能拷问器

wrk 的特点就一个字:快。它是用 C 写的,基于多线程和 epoll 事件驱动,单机就能打出几十万的 QPS。

用法很简单:

wrk -t12 -c400 -d30s http://target.com/api

意思是开 12 个线程,维持 400 个连接,持续压 30 秒。输出结果清晰明了。

但 wrk 有个硬伤——不支持自定义协议。它只能压 HTTP/1.1。你要压 WebSocket 或 gRPC,它无能为力。

不过你要是想快速评估一台服务器的原始吞吐能力,wrk 是最佳选择。

3.5 ab —— 轻量级狙击手

ab(Apache Bench)是 Apache 自带的压测工具。比 wrk 还简单,一条命令搞定:

ab -n 10000 -c 100 http://target.com/

发 10000 个请求,100 个并发。但它只能压 HTTP,且不支持 HTTPS(需要编译时开启 SSL 支持)。

我一般只在开发环境快速验证时用它。比如代码改了个循环逻辑,本地跑一下 ab 看有没有明显变慢。一旦进入正式压测阶段,我肯定换工具。

3.6 Gatling —— 高性能 DSL 选手

Gatling 用 Scala 的 DSL 编写压测脚本,底层是 Akka 的异步非阻塞模型。它的代码可读性很强:

class BasicSimulation extends Simulation {
  val httpConf = http.baseUrl("https://target.com")
  val scn = scenario("Basic")
    .exec(http("request").get("/"))
    .pause(2)
  setUp(scn.inject(atOnceUsers(100)).protocols(httpConf))
}

看着是不是像自然语言?这就是 DSL 的魅力。而且它的 HTML 报告做得极其漂亮,曲线、响应时间分布、吞吐量,一目了然。

但 Gatling 的门槛在于 Scala。如果你团队没人熟悉 Scala,学习曲线会比较陡。我遇到过团队买了一堆 Gatling 的培训课程,最后还是用回 JMeter 的情况。

3.7 怎么选?我的决策逻辑

我画了一张图,帮助你快速定位。

压测工具选型决策逻辑 业务需要压测 需要支持的协议类型? 多协议:JMeter 仅HTTP,继续看 需要极端性能? 是:wrk / ab 看团队语言 Python→Locust Scala→Gatling

简单来说:

  • 做复杂的业务压测(多协议、多步骤、参数关联)→ JMeter
  • 团队擅长 Python → Locust
  • 只想看单机原始性能 → wrk 或 ab
  • 追求高颜值报告和代码维护 → Gatling

3.8 实测经验:不同工具的压测数据差异

我拿一个简单的 REST API(返回 JSON)在同样一台 4 核 8G 机器上做对比。结果很有意思。

工具 最大 QPS 平均延迟 (ms) CPU 占用率 压测机自身瓶颈
JMeter(GUI) 8,200 12.1 65% JVM GC
JMeter(非 GUI) 18,500 5.4 40% 基本无
Locust 15,300 6.5 35% Python GIL
wrk 42,000 2.3 20% 几乎无
ab 12,000 8.3 30% 单进程
Gatling 22,000 4.5 35% Akka 调度

看到没?JMeter 用 GUI 和非 GUI 模式跑,性能差距一倍以上。所以实战中千万别开着 GUI 就跑高并发压测。

重要提醒:wrk 虽然单机性能最强,但它压的是“纯请求”,不包含任何业务逻辑。如果你的接口里有数据库查询、缓存访问,wrk 打出来的 QPS 并不能代表真实用户场景。这一点一定要注意区分。

3.9 总结一下我的选型建议

  • 快速诊断:用 ab 或 wrk,一两分钟看响应
  • 功能压测:用 JMeter,场景编排能力强
  • 持续集成:用 Locust 或 Gatling,代码即脚本
  • 极限性能:用 wrk,压出服务器天花板

你想想看,如果只是验证一个 API 的吞吐量,你拿 JMeter 搭半天脚本,是不是有点杀鸡用牛刀?反过来,如果你要模拟复杂的用户行为,用 ab 一条命令就太粗糙了。

选工具就像选螺丝刀。一字螺丝刀能拧螺丝,十字螺丝刀也能拧。但拧十字螺丝时,用一字刀就容易滑丝。道理是一样的。