3. 基准测试方法论:性能指标定义、工具选择与场景设计

聊到 vLLM 的性能测试,我见过不少团队一上来就开跑,结果测出来的数据自己都看不懂。说白了,基准测试不是跑个数字就完事,你得先搞清楚:你到底要测什么?用什么测?在什么场景下测?

这一节,我就把这三个问题掰开揉碎了讲清楚。嗯,都是我在实际项目中踩过的坑和总结的经验。

3.1 性能指标定义:别被数字骗了

性能指标是基准测试的“度量衡”。定义不清楚,后面的所有工作都是白费。我个人习惯把指标分成两大类:吞吐量类延迟类

3.1.1 吞吐量(Throughput)

吞吐量衡量的是系统在单位时间内能处理多少请求或生成多少 Token。对于 LLM 推理,我们通常关注两个维度:

  • 请求吞吐量(Requests Per Second, RPS):每秒能处理多少个完整的请求。适合衡量系统的并发处理能力。
  • Token 吞吐量(Tokens Per Second, TPS):每秒能生成多少个 Token。这是更细粒度的指标,直接反映模型的生成速度。

我在项目中遇到过一个问题:只看 RPS 很高,但每个请求生成的 Token 数很少,导致 TPS 其实很低。所以,我建议你同时关注这两个指标,才能全面评估系统性能。

3.1.2 延迟(Latency)

延迟是用户体验的“生命线”。对于 LLM 推理,延迟不是单一指标,它包含几个关键阶段:

  • 首 Token 延迟(Time to First Token, TTFT):从发送请求到收到第一个 Token 的时间。这反映了系统的“响应速度”。
  • 每个输出 Token 的时间(Time Per Output Token, TPOT):生成后续每个 Token 的平均时间。这反映了系统的“生成速度”。
  • 端到端延迟(End-to-End Latency):从发送请求到收到完整响应的总时间。

核心观点:TTFT 和 TPOT 是 LLM 推理独有的指标。传统 Web 服务只看端到端延迟,但在 LLM 场景下,用户对“第一个字出来得快不快”和“后续字生成得顺不顺”的感受是完全不同的。

为什么会这样?你想想看,用户等第一个 Token 时是“空等”,焦虑感最强。一旦第一个 Token 出来了,后续的生成是流式的,用户感知到的延迟会大大降低。所以,优化 TTFT 往往比优化 TPOT 更能提升用户体验

3.1.3 指标之间的关系

吞吐量和延迟通常是相互制约的。提高并发数,吞吐量会上升,但延迟也会随之增加。你需要找到一个平衡点。

指标 定义 关注点 优化方向
TTFT 首 Token 延迟 响应速度 减少 Prefill 阶段耗时
TPOT 每个输出 Token 的时间 生成速度 优化 Decode 阶段效率
RPS 每秒请求数 并发处理能力 提升 Batch Size 和调度效率
TPS 每秒 Token 数 生成吞吐量 提升模型推理速度和硬件利用率

3.2 测试工具选择:工欲善其事,必先利其器

选工具这件事,我踩过不少坑。一开始图省事用通用压测工具,结果发现根本测不准 LLM 场景。后来我总结了一套选择逻辑:

3.2.1 vllm-bench:官方标配,首选

vllm-bench 是 vLLM 官方提供的基准测试工具。它最大的优势是原生支持 LLM 推理场景,能准确测量 TTFT、TPOT 等指标。

# 基本用法
vllm-bench --model meta-llama/Llama-2-7b-hf \
           --request-rate 10 \
           --num-prompts 1000 \
           --max-concurrency 8

我个人习惯用 vllm-bench离线测试,因为它能精确控制请求的到达模式,方便复现问题。

小技巧:使用 --request-rate 参数模拟泊松分布到达的请求流,这比固定间隔的请求更接近真实场景。

3.2.2 wrk:轻量级,适合快速验证

wrk 是一个通用的 HTTP 压测工具,轻量、高效。但它不感知 LLM 的流式输出,只能测量端到端延迟。

# 简单压测
wrk -t 4 -c 100 -d 30s http://localhost:8000/v1/completions

我曾经用 wrk 做过一次快速对比测试,发现它测出来的延迟比实际偏高。原因很简单:wrk 会等待完整响应才记录时间,而 LLM 的流式响应在第一个 Token 出来时就已经开始返回了。所以,wrk 更适合做粗粒度的吞吐量测试

3.2.3 Locust:灵活,适合复杂场景

Locust 是一个基于 Python 的负载测试工具,灵活性极高。你可以编写自定义的测试逻辑,模拟用户行为。

from locust import HttpUser, task, between

class LLMUser(HttpUser):
    wait_time = between(1, 5)
    
    @task
    def send_request(self):
        payload = {
            "prompt": "What is the capital of France?",
            "max_tokens": 100,
            "stream": True
        }
        with self.client.post("/v1/completions", json=payload, stream=True) as resp:
            for chunk in resp.iter_lines():
                # 模拟流式读取
                pass

我建议用 Locust 做在线测试,因为它能模拟真实用户的思考时间和行为模式。不过,Locust 的学习曲线比前两个工具陡一些。

工具 适用场景 优势 劣势
vllm-bench 离线测试、指标精确测量 原生支持 LLM 指标 灵活性有限
wrk 快速验证、吞吐量测试 轻量、高效 不感知流式输出
Locust 在线测试、复杂场景模拟 灵活、可编程 学习成本较高

3.3 测试场景设计:别在理想环境下测

很多人在测试时喜欢用“理想环境”:单请求、无并发、短序列。这种测试结果除了自我安慰,没有任何实际意义。你需要设计贴近真实部署场景的测试。

3.3.1 在线场景 vs 离线场景

  • 在线场景(Online):模拟实时交互,请求到达时间随机,对延迟敏感。适合用 Locust 或 vllm-bench 的泊松分布模式。
  • 离线场景(Offline):模拟批量处理,请求集中到达,对吞吐量敏感。适合用 vllm-bench 的固定速率模式。

我记得有一次帮客户做性能评估,他们只测了离线场景,结果上线后用户反馈“太慢了”。后来发现,在线场景下的 TTFT 比离线场景高了 3 倍。所以,一定要根据你的业务场景选择测试模式

3.3.2 不同并发数的测试

并发数是影响性能的关键因素。我建议你至少测试 3 个并发级别:

  1. 低并发(1-4):测试系统的基线性能,了解单请求的延迟上限。
  2. 中并发(8-32):模拟正常负载,观察吞吐量和延迟的变化趋势。
  3. 高并发(64-256):测试系统的极限能力,找到性能拐点。

避坑指南:我曾经在测试高并发时,发现延迟突然飙升。排查了半天,原来是 vLLM 的调度器在处理大量请求时出现了锁竞争。所以,高并发测试不仅能测性能,还能帮你发现系统瓶颈。

3.3.3 测试场景设计示例

下面是一个我常用的测试矩阵:

场景 并发数 请求数 输入长度 输出长度 工具
基线测试 1 100 128 128 vllm-bench
在线负载 16 500 256 256 Locust
高吞吐测试 64 1000 512 512 vllm-bench
极限压测 128 2000 1024 1024 wrk

3.4 知识体系总览

为了让你更直观地理解这一章的内容,我画了一张图:

基准测试方法论知识体系 性能指标定义 吞吐量 延迟 RPS / TPS TTFT / TPOT 测试工具选择 vllm-bench wrk Locust 测试场景设计 在线场景 离线场景 低并发 高并发 核心原则:指标先行 → 工具匹配 → 场景覆盖 避免“跑完数据才发现测错了”的尴尬

这张图把三个核心模块串起来了。你从左边开始,先定义指标,再选工具,最后设计场景。每一步都环环相扣。

好了,这一章的内容就到这里。记住:基准测试不是跑个分,而是为了理解系统的行为边界。下一章,我们会深入具体的测试执行流程和数据分析方法。


专注资料整理