用Locust和k6测试推理服务接口负载
讲解如何构造 Locust 用户任务与 k6 负载场景,让并发用户、运行时长、请求样本和验收阈值保持可对照,并通过 CSV 与退出状态识别失败和延迟瓶颈。
用 Locust 和 k6 测试推理服务接口负载时,应先固定端点、请求体、并发规模与失败判定,再逐级升压并保存结果;Locust 用来构造用户任务,k6 用来控制虚拟用户、运行时长和阈值。做大模型部署容量验证时,两套工具必须调用同一接口并发送等价请求,否则差异可能来自负载模型,而不是被测服务。
大模型部署前先冻结测试口径
开始前建立一份由两套工具共用的测试清单:
- 固定服务地址、接口路径、鉴权方式和请求样本;不要让每个用户临时生成不同长度的输入。
- 明确成功条件:分别检查 HTTP 状态、响应结构和必要内容。只有状态成功而响应为空,不能算接口通过。
- 固定模型标识、生成参数、并发变量和观察窗口。每次只改变一个负载变量,否则无法判断变化来自请求量还是服务行为。
- 记录服务拓扑和运行参数。若负载发生器与被测服务共用机器,还要先排除 CPU、内存和网络争用带来的干扰。
vLLM 的 OpenAI 兼容服务器文档 说明,其 HTTP server 实现了 OpenAI Completions API 和 Chat API:/v1/completions 只适用于文本生成模型,而且不支持 suffix;/v1/chat/completions 需要 chat template,并会忽略 user 参数。不要让 Locust 与 k6 混用这些接口差异。
用 Locust 构造任务并控制并发
Locust 的 locustfile 编写说明 要求有效文件至少包含一个继承 User 的类,HttpUser 会提供 HTTP 客户端。每个模拟用户运行在独立的 gevent greenlet 中,同一任务代码顺序执行,因此“用户数”不能直接等同于同时在途的请求数。任务默认随机选择,也可以使用 @task(n) 设置权重。
先用接近真实调用比例的任务做短时基线。官方示例中的等待配置是:
wait_time = between(1, 5)
这表示每个模拟用户在一个任务结束后等待 1 到 5 秒。固定请求内容时,不要让等待区间和任务权重随运行时间变化,否则两轮结果不可比。
按 Locust 的 无界面运行说明,可以先使用官方示例命令:
locust -f locust_files/my_locust_file.py --headless -u 100 -r 5
这里 -u 设置用户数;-r 是每秒启动用户数,定义见 Locust 配置说明。先确认小规模基线,再逐轮提高 -u,并记录每轮的 -r。启动速率过大时,应用可能尚未完成爬升就进入高负载。
需要限定运行时,可以使用另一个官方示例:
locust --headless -u 100 --run-time 1h30m
-t/--run-time 的默认单位是秒,计时从测试开始。只要出现失败样本,Locust 默认以状态码 1 退出;需要改变该行为时再使用 --exit-code-on-error。启用 --csv 后会生成三类文件:
YOUR_VALUE_stats.csv
YOUR_VALUE_stats_history.csv
YOUR_VALUE_failures.csv
结合统计历史观察阶段变化,并单独检查失败样本,不要只看进程是否正常结束。
用 k6 设置虚拟用户与验收阈值
k6 的 运行说明 将 VU 定义为对脚本默认函数的并行循环。可以先用官方基础命令:
k6 run --vus 10 --duration 30s script.js
其中 10 个 VU 运行 30s 只是文档示例,不是容量结论。先完成功能校验,再逐轮调整 --vus 或 --duration,每轮保持请求体、端点和成功判定不变。
根据 k6 的 阈值文档,thresholds 是指标的通过或失败条件,官方示例包括:
http_req_failed: ['rate<0.01'],
http_req_duration: ['p(95)<200'],
这两条表达式是文档示例,不应直接当作你的服务目标;应按已经确定的验收标准填写。只要阈值未满足,k6 就会以失败结束并返回非零退出状态,因此可以用于流水线判定。
怎样确认测试真的有效
先做功能预检,再做负载测试:手动发送一条与脚本完全相同的请求,确认端点、鉴权、模型标识和响应内容都正确。随后从低负载开始,逐级增加用户数或 VU,并让 Locust 与 k6 使用相同的请求样本和成功判定。
比较结果时至少回答三个问题:失败是否来自业务响应而非脚本错误;延迟上升是否出现在稳定负载阶段;两套工具的变化趋势是否一致。若接口流式返回,还要分别记录首个响应和后续响应间隔,否则整次请求耗时无法说明延迟发生在开始阶段还是生成阶段。只有排除输入变化、鉴权错误和负载发生器资源争用后,才有依据把退化列为被测服务的容量瓶颈候选。
常见出错点
- 只提高并发,不记录启动速率、等待时间和运行时长,最后无法解释请求从哪一轮开始积压。
- Locust 与 k6 使用不同端点、不同参数或不同输入长度,把场景差异误判成工具差异或服务瓶颈。
- 把文档中的阈值示例当成自己的验收线,或者只看平均耗时而忽略失败样本和延迟分布。
- 在同一台机器上同时运行重负载生成器和推理服务,使 CPU、内存或网络争用进入结果。
- 把首次爬坡阶段与稳定阶段混在一起,导致不同轮次的统计区间无法比较。
本文步骤均按正文所链接的官方文档整理,未运行或测量;使用前请按当前版本再次核对。