Locust 用 Python 描述模拟用户行为,再统计请求响应与失败情况。理解它的第一步,是把用户数、用户启动速率和每秒请求数分开:创建100个用户,不表示每秒发送100个请求;每秒启动10个用户,也不是10 RPS。

一个用户会反复执行任务

下面是面向 Locust 2.x 的教学示例。它只读取测试环境的条目接口,不包含真实账号、下单或写数据步骤;目标地址应在获准的隔离测试环境单独配置。阅读或保存脚本不等于已经进行测试,不应直接对公共服务启动负载。

import random
from locust import HttpUser, task, between

class CatalogUser(HttpUser):
    wait_time = between(1, 3)

    def on_start(self):
        # 每个模拟用户的初始化;不把初始化当成随机业务任务
        self.item_ids = (1, 2, 3)

    @task(1)
    def list_items(self):
        self.client.get("/items", name="/items")

    @task(2)
    def view_item(self):
        item_id = random.choice(self.item_ids)
        with self.client.get(
            f"/items/{item_id}",
            name="/items/[id]",
            catch_response=True,
        ) as response:
            if response.status_code != 200:
                response.failure("unexpected HTTP status")
                return
            try:
                payload = response.json()
            except ValueError:
                response.failure("response is not JSON")
                return
            if not isinstance(payload, dict) or payload.get("id") != item_id:
                response.failure("unexpected item")

HttpUser 提供HTTP客户端,每个用户在自己的greenlet中运行。wait_time 在任务完成后产生等待;普通任务内的代码仍按顺序执行。它不是自动加载图片、运行JavaScript和渲染页面的真实浏览器。Locust脚本编写说明

若业务需要登录,可在 on_start 中处理每用户初始化,并使用专用测试账号和安全配置;不要把登录误放进随机任务导致反复登录。初始化失败也须明确处理,不能让未授权请求混入正常样本。

权重是选择概率,不是固定请求比例

示例中查看详情的选择权重是列表的两倍;每一轮选择是随机的,不保证任意短时间窗口恰好1∶2。如果任务各包含不同数量的请求,或者耗时不同,请求统计比例更不能直接等同于权重。

粗略理解稳态流量时,可把每用户的一轮想成“任务耗时+等待时间”。用户数固定后,服务响应变慢也会影响实际请求速率;要以统计到的吞吐和响应时间为准,而非只看配置。

成功码与业务成功分别判断

示例用 catch_response=True 将“返回200但JSON不符合约定”标为失败;name 把动态ID聚合到统一统计名,避免每个ID产生一行难以比较的结果。断言应来自实际接口契约,不要无条件把HTTP错误改报成功。

阅读结果至少同时看用户数、RPS、失败率、响应时间分位数与稳定阶段。平均值可能掩盖慢尾部;把升压期、稳态和停止阶段混在一起,也可能误读容量。Locust统计与使用说明

分布式只是扩展负载发生能力

Master负责协调与汇总,Worker实际生成流量。Web界面便于交互配置,无头模式适合自动化;多Worker并不证明能达到某个并发规模,还要监控发生器CPU、网络、连接和目标系统的瓶颈。Locust分布式运行

试验前要明确目标授权、隔离数据、速率上限和停止条件,低负载验证脚本后再逐步加压。报告中记录Locust/Python版本、脚本、目标配置及原始统计,才能讨论测得的容量;不以工具名称推导“百万并发”或优于另一工具的结论。