测试工具选型:wrk、ab、locust、JMeter对比与Python自建脚本

做性能测试这么多年,我见过太多团队一上来就选工具。有人觉得JMeter万能,有人迷信wrk够快。其实选错工具,后面全白干。这一章,我把主流工具掰开揉碎讲清楚。

核心观点:没有最好的工具,只有最合适的场景。选型前先搞清楚你的目标——是测极限吞吐,还是模拟复杂业务流?

2.1 主流工具速览

先看一张总览图,把几个工具的核心定位搞清楚。

HTTP压测工具选型全景图 HTTP压测工具 wrk ab Locust JMeter C语言编写 Lua脚本扩展 高并发低资源 Apache自带 单线程模型 适合简单GET Python编写 分布式原生 Web UI控制 Java GUI 插件生态丰富 学习曲线陡 推荐组合:wrk(极限吞吐)+ Locust(复杂场景)+ Python(定制化)

2.2 逐个拆解

wrk — 极限吞吐之王

wrk是我个人最常用的工具。它用C写的,底层基于epoll/kqueue,单机就能压出几十万QPS。我习惯用它做快速摸底——新服务上线,先跑一轮wrk看看天花板在哪。

使用技巧:wrk的Lua脚本可以定制请求,但别写太复杂逻辑,否则会拉低压测机性能。

# 基础用法
wrk -t12 -c400 -d30s http://target.com/api

# 带Lua脚本
wrk -t4 -c200 -d60s -s custom.lua http://target.com/api

不过wrk有个硬伤——不支持分布式。单机压不动的时候,你得自己搭多台机器拼数据。另外,它只支持HTTP/1.1,HTTP/2就别想了。

ab — 简单但够用

ab是Apache自带的工具,装好Apache就能用。说实话,它的功能很简陋,但胜在零依赖。我有时候在客户现场,机器上啥都没有,直接apt-get install apache2-utils就能开干。

# 基础用法
ab -n 10000 -c 100 http://target.com/api

# 带Keep-Alive
ab -k -n 10000 -c 100 http://target.com/api

注意:ab是单线程模型,并发高了容易成为瓶颈。我曾经用ab压5000并发,结果压测机自己先挂了。超过1000并发,建议换wrk。

Locust — 模拟真实用户

Locust用Python写,最大的特点是每个用户是一个协程。你可以写Python代码定义用户行为——登录、浏览、下单,一套流程走下来。我在做电商压测时特别喜欢用它,因为能模拟真实用户的思考时间。

from locust import HttpUser, task, between

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

    @task
    def browse_product(self):
        self.client.get("/product/123")
        self.client.post("/cart/add", json={"product_id": 123})

Locust原生支持分布式,Web UI可以实时看结果。但它的性能不如wrk——毕竟每个用户是Python协程,开销比C大。我一般用它做场景压测,不用它测极限吞吐。

JMeter — 重型武器

JMeter功能最全,插件生态也最丰富。从HTTP到JDBC、JMS、FTP,几乎啥都能测。它的GUI界面拖拽式配置,对新手友好。但说实话,我很少用JMeter做纯HTTP压测——太重了。

我的经验:JMeter适合做复杂业务链路的压测,比如一个下单流程涉及5个接口、3个数据库、2个MQ。这时候JMeter的断言、监听器、逻辑控制器就派上用场了。

JMeter的坑也不少。GUI模式跑压测会消耗大量资源,一定要用命令行模式。另外,它的报告虽然好看,但数据准确性有时存疑——我遇到过聚合报告和监听器数据对不上的情况。

2.3 Python自建压测脚本

有时候现成工具都不够灵活。比如你要测一个WebSocket长连接,或者要自定义协议。这时候,自己写脚本最靠谱。

我常用的方案是aiohttp + asyncio。Python的异步IO可以轻松拉起几千个连接,配合uvloop性能还能再提一截。

import asyncio
import aiohttp
import time

async def send_request(session, url):
    async with session.get(url) as resp:
        return await resp.text()

async def main():
    url = "http://target.com/api"
    concurrency = 500
    tasks = []

    async with aiohttp.ClientSession() as session:
        for _ in range(concurrency):
            tasks.append(send_request(session, url))
        start = time.time()
        results = await asyncio.gather(*tasks)
        elapsed = time.time() - start
        print(f"完成 {len(results)} 请求,耗时 {elapsed:.2f}s")

asyncio.run(main())

避坑指南:我曾经用Python自建脚本压测,结果发现连接数上不去。后来排查发现是ulimit没改。记得先执行ulimit -n 65535,否则连接数卡在1024。

自建脚本的优势是灵活,但劣势也很明显——你得自己处理数据采集、结果统计、错误重试。我一般只在工具搞不定的时候才用。

2.4 工具对比表

维度 wrk ab Locust JMeter Python自建
语言 C C Python Java Python
极限QPS 极高 中等 中等 中等 高
分布式 不支持 不支持 原生支持 支持 自实现
场景模拟 弱 极弱 强 极强 自定义
学习成本 低 极低 中 高 中
报告能力 弱 弱 中 强 自实现
适用场景 极限吞吐 快速验证 用户模拟 复杂链路 定制协议

2.5 选型策略

说了这么多,到底怎么选?我总结了一个三步法:

  1. 先看目标——测极限QPS还是测业务场景?前者选wrk,后者选Locust或JMeter。
  2. 再看环境——客户机器上啥都没有?用ab。团队有Python基础?用Locust。
  3. 最后看复杂度——单接口压测用wrk,多接口链路用JMeter,特殊协议自己写。

我的推荐组合:wrk做快速摸底 + Locust做场景压测 + Python脚本兜底。三件套覆盖90%的场景。

嗯,工具选型就聊到这儿。记住一点——工具是手段,不是目的。搞清楚你要测什么,再选工具,别反过来。