4. Locust 实战:从安装到分布式压测
Locust 这个工具,我用了好几年了。说实话,刚开始接触压测工具时,JMeter 用得比较多。但后来发现,用 Python 写压测脚本实在太灵活了。Locust 的核心思想很简单——每个用户就是一只蝗虫,你想想看,成千上万只蝗虫一起啃食你的系统,吞吐量自然就上去了。
这一章,我们直接上手。从安装开始,到写一个完整的 User 类,再到分布式压测和 Web UI 监控。我会把项目中踩过的坑都告诉你。
4.1 安装 Locust
安装没什么难度。用 pip 一行搞定:
pip install locust
我个人习惯用虚拟环境,避免污染全局 Python。如果你也这么干:
python -m venv locust_env
source locust_env/bin/activate # Windows 用 locust_env\Scripts\activate
pip install locust
验证安装:
locust --version
看到版本号就说明成了。嗯,这里要注意——如果你在公司内网,记得配好代理或使用离线包。我曾经在客户现场折腾了半小时,才发现是网络问题。
4.2 编写第一个 User 类
Locust 的核心是 User 类。每个虚拟用户就是一个 User 实例。我们来看一个最简单的例子:
from locust import User, task, between
class MyUser(User):
wait_time = between(1, 3)
@task
def hello(self):
print("执行用户任务")
这个类干了三件事:
- 继承
User基类 - 设置等待时间
wait_time,模拟用户思考间隔 - 用
@task装饰器标记任务方法
运行它:
locust -f my_user.py
然后打开浏览器访问 http://localhost:8089,就能看到 Web UI 了。
wait_time 除了 between,还可以用 constant(固定间隔)或 constant_pacing(固定吞吐间隔)。我常用 between,更贴近真实用户行为。
4.3 HttpUser 与 TaskSet
实际压测中,我们压的是 HTTP 接口。Locust 提供了 HttpUser,它自带一个 client 属性,本质上是 requests.Session 的封装。
from locust import HttpUser, task, between
class WebsiteUser(HttpUser):
wait_time = between(0.5, 2.5)
@task
def index(self):
self.client.get("/")
@task(3)
def about(self):
self.client.get("/about")
看到 @task(3) 了吗?这是权重。about 页面被访问的概率是 index 的 3 倍。我一般用权重来模拟不同接口的调用比例。
当任务变多时,TaskSet 就派上用场了。它可以把一组任务组织起来:
from locust import HttpUser, task, between, TaskSet
class UserBehavior(TaskSet):
def on_start(self):
"""用户启动时执行一次,比如登录"""
self.client.post("/login", {"username": "test", "password": "123"})
@task(2)
def view_items(self):
self.client.get("/items")
@task(1)
def buy_item(self):
self.client.post("/buy", {"item_id": 1})
class WebsiteUser(HttpUser):
tasks = [UserBehavior]
wait_time = between(1, 2)
on_start 方法很实用。我在项目中用它做登录、获取 token、初始化数据。这样每个虚拟用户启动时都会先登录,后续任务带着 token 跑。
on_start 里的操作会计入压测数据。如果你不想让登录请求污染结果,可以在统计时过滤掉。我一般单独记录登录的成功率。
4.4 分布式压测
单机压测,说白了就是一台机器模拟用户。但当你需要上万并发时,单机的 CPU、内存、网络连接数都会成为瓶颈。这时候就需要分布式压测。
Locust 的分布式架构很简单:
- Master 节点:负责协调、收集数据、提供 Web UI
- Worker 节点:真正产生压力的机器
启动方式:
# 先启动 master
locust -f my_user.py --master
# 再启动 worker(可以多台机器)
locust -f my_user.py --worker --master-host=192.168.1.100
这里有几个关键点:
| 参数 | 说明 | 我的建议 |
|---|---|---|
--master |
以主节点模式运行 | master 本身不产生压力,资源消耗很小 |
--worker |
以工作节点模式运行 | worker 机器配置越高越好,尤其是 CPU |
--master-host |
指定 master 的 IP | 确保 worker 能访问 master 的 5557 端口 |
--expect-workers |
期望连接的 worker 数量 | 等所有 worker 就绪后再开始压测 |
下面这张图展示了 Locust 的分布式架构:
4.5 Web UI 监控
启动 Locust 后,默认会在 8089 端口开启 Web UI。这个界面很直观:
- Start 页面:设置总用户数、每秒孵化数、目标 Host
- Statistics 页面:实时显示每个接口的请求数、失败数、响应时间、RPS
- Charts 页面:折线图展示吞吐量、响应时间、用户数变化
- Failures 页面:列出所有失败的请求及错误原因
- Exceptions 页面:显示脚本中抛出的异常
我一般重点关注三个指标:
| 指标 | 含义 | 健康值参考 |
|---|---|---|
| RPS | 每秒请求数,即吞吐量 | 越高越好,但要看系统承受能力 |
| 95% 响应时间 | 95% 的请求在多少毫秒内完成 | 一般要求 < 500ms |
| 失败率 | 失败请求占比 | 应 < 1%,最好为 0 |
Web UI 还支持 CSV 导出。压测结束后,点一下「Download Data」就能拿到原始数据。我通常用这些数据做后续分析,或者生成报告。
4.6 命令行模式
有时候你不想开浏览器,或者要在 CI/CD 里跑压测。Locust 支持无头模式:
locust -f my_user.py --headless -u 1000 -r 100 --run-time 5m --host=https://example.com
参数说明:
-u 1000:模拟 1000 个用户-r 100:每秒孵化 100 个用户--run-time 5m:运行 5 分钟--host:目标地址
运行结束后,终端会直接打印统计结果。我经常把它写进 Jenkins 任务里,每天凌晨跑一次,监控系统性能变化。
--only-summary,只在结束时打印汇总数据。或者用 --csv 导出到文件。