vLLM:实验与项目
本章是待执行的 GPU/分布式实验方案,不是已完成的 benchmark。本地源码已经补齐,关键入口见 08 源码教材;无 GPU 的可运行练习见 10 实践教材。CUDA、Nsight 和分布式性能实验建议使用版本兼容的 Linux GPU 环境。
1. 按资源选择实验
| 条件 | 可以完成 | 不能据此推断 |
|---|---|---|
| 只有本机 CPU | 公式、状态机、源码阅读、小型 Tensor/缓存模拟 | CUDA kernel 与 RDMA 性能 |
| 单张 GPU | 基线、调度、APC、CPU/磁盘缓存、部分 profiling | 多卡扩展效率和真实 PD 集群成本 |
| 多 GPU 单机 | TP 对照、PD 基础功能、共享内存/本机数据路径 | 跨节点拥塞和 RDMA 扩展 |
| 多节点、普通网络 | 分布式缓存语义、TCP 路径和失败恢复 | 高速 RDMA 的性能收益 |
| 多节点、RDMA | Mooncake 传输、PD、共享存储的端到端性能 | 未测试硬件/模型上的泛化收益 |
先选能容纳权重、KV 和运行开销的小模型;固定模型 revision、tokenizer、dtype 和生成设置。用较小模型学习系统机制,再逐步扩大负载。
2. 公共实验规则
- 使用版本模板保存完整环境和配置。
- 区分引擎冷启动、kernel/graph warmup、KV 缓存冷暖和稳态。
- 每次只改变一个主要因素;交替实验顺序并重复运行。
- 固定实际 token 长度分布,记录 EOS/停止条件造成的长度偏差。
- 基线避免无意重复长前缀;缓存实验则显式控制共享前缀。
- 同时记录完成、失败、拒绝、客户端排队和实际发送速率。
- 精确复用做数值/生成结果对照;量化和 CacheBlend 单独做质量评估。
- P99 需要足够样本;几十个请求只适合功能检查,不适合尾延迟结论。
- 区分“每请求命中”“token 命中”“字节命中”,并记录查询分母。
- 系统层与阶段指标可能重叠,不能把重叠时间简单相加解释端到端耗时。
可从以下官方命令入口检查所选版本支持的参数:
vllm --version
vllm serve --help
vllm bench serve --help
部署和 connector 配置使用对应官方资料,不要跨 vLLM/LMCache 版本抄参数。保存完整启动命令、配置文件与服务日志。
3. E1:单卡服务基线
问题:该模型在目标硬件上,吞吐与延迟随负载怎样变化?
| 负载 | 输入 / 输出 token 示例 | 主要观察 |
|---|---|---|
| 短输入短输出 | 128 / 128 | launch、CPU、交互延迟 |
| 长输入短输出 | 4096 / 128 | Prefill、TTFT、缓存价值 |
| 短输入长输出 | 128 / 1024 | Decode、ITL、KV 增长 |
| 混合负载 | 上述按固定比例混合 | 长短请求干扰与尾延迟 |
操作:
- 完成单请求正确性和流式输出检查。
- warmup 引擎,先进行并发 1 的基线,再按容量扫描并发,例如 4、16、32。
- 单独做开放式到达率扫描,从稳定低负载逐步接近饱和;不要将其与闭环并发曲线混画。
- 保存 TTFT/TPOT/ITL/E2E 分布、输入/输出 tokens/s、Goodput、失败与拒绝。
- 观察 CPU、GPU、KV block 使用、队列和抢占。
产出:负载—延迟—吞吐曲线,明确 SLO 下的稳定运行区间。不要仅报告最大 tokens/s。
4. E2:KV 容量与分页验证
问题:模型配置能否解释真实 KV 容量和并发限制?
操作:
- 从实际模型配置读取层数、KV heads、head dimension、attention 类型和 dtype。
- 按每层真实状态计算单 token KV,比较引擎日志中的 KV 容量。
- 在固定并发下改变上下文长度;在固定长度下改变并发。
- 记录 block 分配、缓存共享与抢占,区分 pool 已分配内存与正在使用的 blocks。
- 手动模拟两个请求共享完整前缀,分别结束后检查引用何时归零。
产出:预测/观测容量对照表,解释 block 取整、workspace、并行复制或特殊模型导致的差异。
不能只通过设备显存不下降判断释放失败;预分配 pool 和有效缓存可能仍保留内存。
5. E3:调度与 Chunked Prefill
问题:长 prompt 怎样影响 Decode?token budget 的收益边界在哪里?
操作:
- 建立一组持续 Decode 的请求,再注入固定比例的长 prompt。
- 选择模型和版本允许的数个 token budget,保持其他参数相同。
- 记录长 prompt 的 TTFT,以及正在 Decode 请求的 ITL 分布。
- 检查更大 budget 是否提高计算效率,以及是否增加执行步时间和尾延迟。
- 用 profiler 对齐长 Prefill、kernel 执行与 ITL 尖峰。
产出:TTFT—ITL—Goodput 的取舍图。结论应说明适用的长度和到达率,不写“越大越好”或“越小越好”。
6. E4:vLLM 本地 Prefix Cache
问题:相同前缀节省多少 Prefill?哪些变动会使复用失效?
设计四组输入:
| 组 | 变化 | 要验证的机制 |
|---|---|---|
| A | 完全相同长前缀,不同问题后缀 | 普通前缀命中 |
| B | 长前缀的早期 token 改变 | 前序变化使后续完整前缀身份改变 |
| C | 只在接近末尾的位置改变 | 复用深度与 block 粒度 |
| D | 同一文档放到不同前文后 | 普通缓存不能任意复用非前缀文档 |
先检查 tokenize 后的实际共同 token 长度;字符串拼接和模板边界可能影响它。隔离其他外部缓存,并分别控制本地 APC 开关或冷暖状态。
记录本地命中 token、实际计算 token、TTFT、KV 占用和输出对照。全命中后可能仍需计算尾部 token,不将这个现象直接判为 bug。
产出:命中深度与 TTFT 的对应关系,以及早期 token 改变造成的后续缓存失配示例。
7. E5:LMCache 的分层取回
问题:本地 HBM 之外的缓存是否比重新 Prefill 更划算?
至少比较:
| 组 | 条件 |
|---|---|
| 基线 | 不使用外部缓存,控制本地命中 |
| HBM | 本地 APC 热命中 |
| CPU | 本地 HBM miss,但 LMCache CPU 层有兼容对象 |
| L2 | L1 miss、L2 hit,确认真实取回路径 |
| 全 miss | 各层均未命中,测量额外查找和保存成本 |
操作:
- 使用所选版本支持的 LMCache 模式,记录 in-process 或 MP。
- 用独立测试命名空间准备冷数据,再用固定请求填充。
- 在不清除待测外部层的前提下,控制引擎本地命中;例如使用兼容的新实例,但先确认对象身份可共享。
- 扫描 prompt 长度、chunk 粒度和并发,读取实际协商后的 chunk size。
- 记录 lookup、retrieve、H2D、重排、等待和剩余 Prefill 的时间,以及保存成本。
- 对照输出和任务质量,检查失败回退是否重新计算了正确范围。
产出:对该模型和硬件的“取回/重算临界区间”。区分同进程内复用、跨进程共享和真正远端读取。
8. E6:Mooncake Store 与两条集成路线
问题:直接 Store connector 与 LMCache 的 Mooncake 后端分别增加了什么能力和成本?
路线:
A:vLLM → MooncakeStoreConnector → Mooncake Store
B:vLLM → LMCache → Mooncake Store
操作:
- 固定 Store 拓扑和模型,分别建立兼容配置。
- 确认一个实例保存的数据能被另一个兼容实例读取。
- 对比全 miss、远端 warm hit、热点多读者、容量压力下驱逐。
- 记录元数据请求、payload 字节、有效带宽、缓存容量和端到端指标。
- 若测试 TCP/RDMA,确认实际 backend 与 GPU/CPU 数据路径,而不是只看启动配置。
- 区分 Store Master 的元数据工作与 Transfer Engine 的数据传输。
不同路线不一定有相同默认 chunk、保存策略和本地缓存层。先报告配置差异,再解释结果,不能把所有性能差距归因于“多一层”。
产出:职责、能力、开销与排障入口的对照表。没有 RDMA 时,明确只验证了 TCP/可用路径。
9. E7:PD 分离
问题:PD 在什么负载与 SLO 下值得使用?
比较共置服务与 PD 时,固定总 GPU 数量和型号,记录 CPU、内存、网络、存储资源。两套方案可以分别合理调优,但必须公开调优范围。
操作:
- 先建立模型、dtype、layout 和并行兼容的 P/D 组合。
- 确认 prompt 身份、KV 范围、首 token/尾部重算行为与完成通知。
- 测量低负载单请求,分解额外传输成本。
- 增加长短混合请求,到达率逐步升高,比较 TTFT/TPOT 目标下的 Goodput。
- 调整 P:D 资源比例,记录两侧排队与利用情况。
- 有资源时测试不同网络条件;非对称 TP 仅在 connector 明确支持时进行。
产出:PD 的收益区间与退化区间。若只发现尾延迟改善而原始吞吐下降,应如实记录。
10. E8:缓存与传输故障
仅在独立实验环境进行,不在共享生产服务上注入故障。
| 故障 | 观察目标 | 正确性判据 |
|---|---|---|
| lookup 后对象不再可用 | 取回失败和回退 | 不跳过未真正加载的 token |
| 传输中客户端取消 | 在途操作与目标 buffer 生命周期 | 不提前复用仍被访问的内存 |
| 请求结束但保存未完 | 源 block 的延迟释放 | 保存结果不混入其他请求内容 |
| Store 慢/不可用 | 超时、重算、队列和背压 | 不永久阻塞;回退并发可控 |
| P 或 D 失败 | pin/lease 与资源回收 | 无永久保留,也不读已复用源块 |
| 修改模型/adapter 身份 | 缓存 namespace | 不复用不兼容 KV |
| 缓存容量耗尽 | 驱逐、admission、回退 | 活跃/受保护对象不被不安全覆盖 |
在可用测试接口中模拟失败比随意破坏底层内存更容易获得可解释结果。记录恢复时间、残留 blocks、失败请求、重算量和新的负载峰值。
产出:至少一个“故障 → 状态变化 → 资源清理 → 回退”的时序图和对应日志证据。
11. E9:CacheBlend 的性能与质量
问题:非前缀片段复用能否在目标 RAG 任务上保持可接受质量并降低 TTFT?
对照三类方案:
- 完整 Prefill,作为任务质量与输出参照。
- 普通精确前缀缓存,仅复用真正相同前缀。
- 支持版本中的 CacheBlend,扫描重算与相关策略。
数据覆盖文档重排、插入新前文、跨文档推理、位置变化和 tokenization 边界。选择任务级指标,例如答案准确率、引用正确性或检索增强任务评分,不能仅检查“输出看起来像一句话”。
同时报告 TTFT、质量、重算 token、取回字节和失败案例。该实验与精确前缀缓存的等价性验证分开;未测质量时,不应下结论称其“无损加速”。
12. 统一结果表
实验 ID / 假设:
环境与配置文件:
模型与实际输入输出长度分布:
缓存冷暖 / 本地与外部命中控制:
并发或到达率 / 实际发送率:
样本数 / 重复次数 / 实验顺序:
成功 / 失败 / 拒绝请求:
TTFT P50/P95/P99:
TPOT 与 ITL 分布:
E2E 分布:
输入 tokens/s / 输出 tokens/s / requests/s:
SLO 定义 / Goodput:
本地命中 / 外部命中 / 各自查询分母:
保存和取回字节 / 有效带宽:
lookup / IO / H2D / 重排 / 排队时间:
KV 使用 / 抢占 / lease超时 / 回退重算:
正确性与质量:
原始数据 / trace / 日志路径:
假设被支持还是被推翻:
可解释的机制:
未解决的问题:
适用边界:
13. 推荐最终项目
项目名称:面向混合负载的 vLLM 与分层 KV Cache 性能分析。
交付内容:
- 一张服务架构图和一张 KV 生命周期图。
- 一份模型/KV/并行容量估算。
- 一组共置服务基线,以及至少一种缓存优化的对照。
- 一个 profiler 或分阶段 trace 支持的瓶颈判断。
- 一个缓存失效/传输失败的正确性案例。
- 一张 SLO 下 Goodput 与成本的对照表。
- 一段明确说明无收益区间的结论。
面试讲解顺序:需求与负载 → 基线 → 证据 → 改动 → 验证 → 代价与边界。不要把未执行的实验、理论带宽或论文结果写成自己的实测数据。