Skip to content

一、为什么选择 Locust? ​

在传统性能测试领域,JMeter 长期占据主导地位,但在面对需要高度定制业务逻辑、动态签名计算或复杂状态机轮询的高并发压测场景时,纯代码驱动的性能工具往往展现出更高的工程灵活性。

Locust 是一款用 Python 编写的开源负载测试工具,核心优势体现在:

  1. 常规代码定义用户行为:无需配置笨重的 XML 或陷入特定 UI 界面,完全使用 Python 标准语法编写测试逻辑。
  2. 底层基于 gevent 协程:单个线程内利用绿色线程(Greenlet)处理非阻塞异步 I/O,单台压测机即可模拟数千个高并发虚拟用户,内存开销极低。
  3. 原生支持分布式扩展:天然支持 Master / Worker 架构,能横向扩展到多台机器分布式压测。
  4. 灵活的协议扩展性:不仅支持 HTTP/HTTPS,只需在客户端提供 Python Socket/TCP/gRPC 驱动,即可测试任何自定义通信协议。

二、Locust 核心架构与运行模型 ​

Locust 的分布式拓扑包含两个核心节点角色:

text
┌────────────────────────────────────────────────────────┐
│                   Master 协调控制节点                    │
│   • 启动/停止负载测试        • 分发并发任务与参数         │
│   • 汇总并实时聚合统计数据   • 提供 Web UI 监控仪表盘     │
└───────────────▲────────────────────────▲───────────────┘
                │ 心跳与聚合指标          │ 指令下发
        ┌───────┴────────┐       ┌───────┴────────┐
        │  Worker 节点 1 │       │  Worker 节点 2 │
        │ (gevent 协程池) │       │ (gevent 协程池) │
        └────────────────┘       └────────────────┘
  • Master 节点:负责集中控制、分发任务以及接收所有 Worker 上报的指标数据,本身不产生实际压测流量。
  • Worker 节点:实际产生并发负载的执行机,每台 Worker 根据分配的虚拟用户数启动协程并发发送请求。

三、测试生命周期与核心 API ​

在编写 Locust 测试脚本时,通常围绕以下三个核心类展开:

1. HttpUser 与并发用户定义 ​

HttpUser 为每个模拟用户注入一个具备会话保持能力(类似 requests.Session)的 client 对象:

python
from locust import HttpUser, task, between

class WebPortalUser(HttpUser):
    # 模拟用户在每个任务执行间隔思考 1 到 3 秒
    wait_time = between(1, 3)

    # 目标压测服务基地址(也可通过命令行 --host 动态注入)
    host = "https://api.example.com"

2. @task 权重控制与任务编排 ​

通过 @task(weight) 可以精准控制不同业务接口的并发流量配比:

python
    @task(3)
    def view_device_list(self):
        """权重为 3:查询设备列表(高频读操作)"""
        self.client.get("/api/v1/devices", headers={"Authorization": "Bearer token"})

    @task(1)
    def export_report(self):
        """权重为 1:导出报表(低频重计算操作)"""
        self.client.post("/api/v1/reports/export", json={"type": "daily"})

3. TaskSet 复杂业务流建模 ​

针对带有前后顺序依赖的多步业务(如:登录 -> 检索设备 -> 下发控制指令 -> 登出),可使用 TaskSet 进行分级封装:

python
from locust import SequentialTaskSet, task

class DeviceInspectionFlow(SequentialTaskSet):
    @task
    def step1_login(self):
        res = self.client.post("/login", json={"user": "tester", "pwd": "123"})
        self.token = res.json().get("token")

    @task
    def step2_check_metrics(self):
        self.client.get("/metrics", headers={"token": self.token})

    @task
    def step3_finish(self):
        self.interrupt() # 完成当前流程,返回上一级

四、事件钩子(EventHook)深度定制 ​

Locust 提供了丰富的生命周期钩子,用于在测试的不同阶段执行初始化或指标清理:

  • test_start:整个测试启动时触发(可用于在 Master 上初始化测试数据);
  • test_stop:测试结束时触发(可用于清理脏数据并归档报表);
  • request:每个 HTTP 请求完成时触发(可用于将响应耗时同步推送到外部监控系统)。
python
from locust import events

@events.test_start.add_listener
def on_test_start(environment, **kwargs):
    print("压测集群已就绪,开始初始化基础数据...")

@events.test_stop.add_listener
def on_test_stop(environment, **kwargs):
    print("压测执行完毕,开始汇总执行结果...")

五、常用命令行运行规范 ​

在持续集成流水线或生产测试中,通常采用 Headless(无界面)模式执行:

bash
# 单机无界面自动化压测:
# -u 500: 总共模拟 500 个虚拟用户
# -r 50: 每秒启动(梯形加压)50 个用户
# -t 10m: 持续运行 10 分钟
# --html: 自动生成完整 HTML 格式测试报告
locust -f load_test.py --headless -u 500 -r 50 -t 10m --html=report.html

分布式集群启动方式:

bash
# 在主节点启动 Master
locust -f load_test.py --master

# 在执行机上启动 Worker(可根据 CPU 核数启动多个 Worker 进程)
locust -f load_test.py --worker --master-host=127.0.0.1

测试开发工程师 · 专注自动化与系统架构 | 邮箱: hansblog@atumsoul.win