推理API通常位于模型服务之上,接收输入文本或图像,返回预测结果。与普通Web接口不同,推理请求的计算密度更高、单次耗时更长,并且受GPU显存、批次大小、队列长度等因素影响明显。直接照搬普通HTTP接口的压测方法,很容易得到与生产环境偏差较大的结论。因此需要从推理链路的真实瓶颈出发,选择适合的工具采集吞吐量、延迟分位数和错误率,并对结果做分层分析。

推理API基准测试的核心指标与工具选型
推理API的性能评估不能只看平均延迟。假设一个接口在1000次请求中,990次都在40毫秒内返回,但有10次因为排队或GC停顿超过了2秒,平均值可能仍然只有60毫秒左右,但用户体验已经受到严重影响。因此基准测试至少要记录P50、P95、P99延迟,以及最大延迟和标准差。吞吐量方面,QPS或RPS表示每秒完成的请求数,但需要区分是请求到达速率还是服务端实际处理速率。错误率同样重要,尤其是在模型推理超时、输入超长或显存不足时,错误率会突然升高。
工具选择上,wrk适合快速获得单机极限吞吐。它基于事件驱动,能用很少的线程模拟数万并发连接,并且支持Lua脚本扩展请求生成逻辑。Locust则更偏向行为模拟和分布式压测。它用Python定义用户行为,每个虚拟用户可以按权重执行不同的任务,还能设置等待时间、思考时间,更接近真实流量。对于推理API,通常先用wrk找出服务的吞吐上限和延迟拐点,再用Locust模拟更复杂的业务场景,比如不同输入长度混合、不同模型路由或带鉴权的请求链。
压测之前还要明确环境隔离。不要对生产环境直接施压,除非已经做好容量规划和流量标记。测试环境应与生产保持相同的GPU型号、推理框架版本和服务配置,否则结果无法迁移。还需要准备足够数量的真实样例数据,避免全部使用固定文本导致缓存命中或算子优化异常。
使用wrk进行高并发吞吐量测试
wrk的安装比较简单,在Linux或macOS上可以从源码编译,也可以使用系统包管理器安装。安装完成后,基础命令即可对HTTP接口发起压力。下面这条命令创建12个线程、保持400个并发连接,持续压测30秒,并输出延迟分布:
wrk -t12 -c400 -d30s --latency \ -s infer.lua \ http://127.0.0.1:8000/v1/infer
如果推理API接收JSON格式的POST请求,需要使用Lua脚本构造请求体。脚本中可以动态修改请求参数,模拟不同长度的输入,避免所有请求完全一致。一个简单的Lua脚本如下:
wrk.method = "POST"
wrk.headers["Content-Type"] = "application/json"
wrk.body = '{"prompt":"你好,请解释一下什么是大模型推理","max_tokens":64}'
对于需要变化输入的场景,可以在request函数中拼接不同内容。例如准备一个样本表,每次随机选择一条,并设置请求超时。wrk默认不会等待响应超过一定时间,但可以通过脚本里的wrk.timeout进行调整。需要特别注意的是,wrk统计的延迟是从请求发出到收到完整响应的时间,不包含DNS、连接建立之外的业务排队,但它能准确反映服务端在持续高并发下的表现。
执行wrk时建议逐步提高并发数,例如从50、100、200、400依次增加到800。每次调整后观察P99和错误率,找到延迟开始急剧恶化的拐点。这个拐点通常对应推理队列开始积压或GPU利用率达到上限。如果QPS还在上升但P99已经超过业务允许范围,说明继续加压没有意义,反而可能掩盖真实的容量边界。压测期间还要监控服务端的GPU利用率、显存占用、CPU使用率和队列长度,否则只看客户端数据无法定位瓶颈。
使用Locust实现可编程的分布式压测
Locust的优势在于可以用Python编写灵活的压测场景。先安装Locust,然后创建一个locustfile.py,定义用户行为和任务权重。针对推理API,通常需要模拟不同输入类型,比如短文本、长文本、多轮对话或图像输入。下面是一个针对文本推理接口的示例:
from locust import HttpUser, task, between
import random
prompts = [
"解释一下什么是推理API",
"请写一段关于性能测试的总结",
"如何在Kubernetes中部署模型服务",
]
class InferenceUser(HttpUser):
wait_time = between(0.5, 1.5)
@task(3)
def short_infer(self):
payload = {
"prompt": random.choice(prompts),
"max_tokens": 32,
"temperature": 0.7,
}
self.client.post(
"/v1/infer",
json=payload,
headers={"Authorization": "Bearer test-token"},
timeout=30,
)
@task(1)
def long_infer(self):
payload = {
"prompt": "请详细分析" + random.choice(prompts) + ",并给出实现方案",
"max_tokens": 256,
"temperature": 0.3,
}
self.client.post(
"/v1/infer",
json=payload,
headers={"Authorization": "Bearer test-token"},
timeout=60,
)
这个脚本定义了两类任务,短推理任务权重为3,长推理任务权重为1,也就是说每4个请求中大约有3个是短推理、1个是长推理。用户等待时间设为0.5到1.5秒之间的随机值,避免请求节奏过于机械。这样压测流量更接近真实用户行为,但也意味着达到高并发需要更多虚拟用户。Locust的并发数由用户数和启动速率决定,例如在Web界面中设置100个用户、每秒启动10个用户,或者在命令行使用--users 100 --spawn-rate 10。
Locust支持分布式运行。在单机无法产生足够压力时,可以启动一个master节点和多个worker节点,每个worker独立向目标服务发送请求,master负责汇总指标。启动方式为:master节点执行locust -f locustfile.py --master,worker节点执行locust -f locustfile.py --worker --master-host=192.168.1.10。需要注意的是,所有worker的压测脚本必须一致,否则行为无法对齐。
Locust的指标面板默认显示请求总数、失败数、平均响应时间和RPS,但也可以通过扩展监听事件记录P95、P99。Web界面中还能实时调整用户数,方便进行阶梯加压。与wrk相比,Locust的客户端本身会消耗更多CPU和内存,单机用户数上限较低,因此更适合场景化压测和波动流量模拟,而不是极限吞吐测试。
压测结果分析与推理API优化方向
拿到wrk和Locust的数据后,需要把客户端指标与服务端监控对应起来。如果P50很低但P99很高,通常说明服务端存在排队、锁竞争或推理批次不均匀的问题。推理服务经常使用动态批次,把多个并发请求合并成一个批次送到GPU,以提高吞吐量。这个机制在并发较高时能显著提升QPS,但如果请求到达不规律,某些请求可能等待批次凑满而延迟增加。此时可以调整最大等待时间、批次大小上限,或者采用连续批处理策略。
错误率突然上升时,优先检查服务端日志中的超时、显存溢出和输入长度限制。例如长文本推理请求如果触发最大token上限,可能返回错误或截断。压测中要记录每次请求的实际输入长度、输出长度和耗时,以便分析是否存在异常慢的样例。GPU利用率是重要信号:如果吞吐量没有达到预期,而GPU利用率一直低于60%,说明瓶颈可能在CPU处理、数据拷贝或模型服务的Python层。反过来,如果GPU利用率已经接近100%但P99仍然很高,说明需要扩大资源或降低单请求计算量。
最后,基准测试应当固化为可重复的流程。每次模型升级、框架更新或配置调整后,用同一组样例和同样的并发阶梯重新测试,并保存结果供对比。一次有效的推理API基准测试,不只是得到一个QPS数字,更重要的是建立延迟、吞吐、错误率和资源占用的对应关系,让团队知道当前服务的容量边界以及下一步该优化哪个环节。
通过wrk快速探查极限吞吐,再用Locust模拟真实业务流量,两者结合能够为推理API提供较为全面的性能画像。压测过程中保持环境一致、监控到位、逐步加压,才能避免被单一指标误导,真正找到推理链路的薄弱点。
推理API性能测试wrk压力测试Locust基准测试修改时间:2026-08-24 14:43:50