测试工具选型:wrk、ab、locust、JMeter对比与Python自建脚本
做性能测试这么多年,我见过太多团队一上来就选工具。有人觉得JMeter万能,有人迷信wrk够快。其实选错工具,后面全白干。这一章,我把主流工具掰开揉碎讲清楚。
核心观点:没有最好的工具,只有最合适的场景。选型前先搞清楚你的目标——是测极限吞吐,还是模拟复杂业务流?
2.1 主流工具速览
先看一张总览图,把几个工具的核心定位搞清楚。
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 选型策略
说了这么多,到底怎么选?我总结了一个三步法:
- 先看目标——测极限QPS还是测业务场景?前者选wrk,后者选Locust或JMeter。
- 再看环境——客户机器上啥都没有?用ab。团队有Python基础?用Locust。
- 最后看复杂度——单接口压测用wrk,多接口链路用JMeter,特殊协议自己写。
我的推荐组合:wrk做快速摸底 + Locust做场景压测 + Python脚本兜底。三件套覆盖90%的场景。
嗯,工具选型就聊到这儿。记住一点——工具是手段,不是目的。搞清楚你要测什么,再选工具,别反过来。