Month 6 · 前沿 serving 系统
从 mini-vLLM 走向生产系统:prefill/decode 分离、KV cache 体系、prefix-aware routing、speculative decoding、FP8/KV 量化、MoE/MLA serving。
M5 结束时,你已经能写一个单机 toy engine。下一步不是把 toy engine 再堆 20 个 feature, 而是学会生产系统在什么约束下选择 feature:什么请求该走 prefix cache,什么请求该拆 prefill/decode, 什么请求投机解码反而变慢,什么时候 KV transfer 会成为新的瓶颈。
01先补知识断层:单机 engine 到生产 serving
这份教材前 5 个月已经把单机 vLLM 的核心闭环走通了:入口、KV 分页、scheduler、kernel、mini-vLLM。 明显的缺口只有一个:你还没把这些模块放进多实例、多 GPU 池、多 SLO、多租户的生产环境里看。
所以后续学习不缺基础,缺的是判断力框架。真实生产里,优化不是越多越好,而是要问: 当前 workload 的瓶颈是 prefill 算力、decode 带宽、KV 容量、KV 传输、还是排队延迟?
02新目标函数:Goodput,而不是 Tokens/s
老 benchmark 喜欢报 tokens/s。生产 serving 更关心:在 TTFT 和 ITL 都满足 SLO 的前提下,每张 GPU 能承载多少请求。 这就是 DistServe 论文强调的 goodput 视角:同样吞吐,如果 p99 ITL 爆掉,它对产品没有价值。
| 指标 | 看什么 | 常见误判 | 应该怎么用 |
|---|---|---|---|
| TTFT | 用户多久看到第一个 token | 只看平均值,忽略长 prompt 的尾部 | 按 prompt length bucket 看 p90/p99 |
| ITL / TPOT | 流式输出是否顺滑 | 把 prefill 和 decode 混在一个延迟里 | decode 阶段单独设 SLO,重点看尾延迟 |
| Queue time | 容量是否已经耗尽 | GPU utilization 高就以为健康 | 排队上升通常比 GPU 利用率更早报警 |
| KV cache usage | 显存是否被上下文吃掉 | 只看 weight 大小,不算 KV | 按模型结构和上下文长度估算 tokens in flight |
| Goodput | 满足 SLO 的请求率 | 吞吐高但 SLO 违约 | 所有优化都用 goodput 对账 |
03Prefill / Decode 分离:为什么它突然成了主线
prefill 和 decode 的资源画像完全不同。prefill 一次吃掉整个 prompt,矩阵乘大、算力密集;decode 每步只生成 1 个 token, 主要被 weight/KV 读取和 kernel launch 限制,常常是 memory-bound。把两者合在一个 batch 里,长 prompt 会打断正在流式输出的请求。
但分离不是免费午餐。你省掉 prefill/decode 干扰的同时,引入了KV transfer: 如果 prompt 很短、模型很小、互联很慢,传 KV 的时间会吃掉收益。生产系统要做的是有条件地分离,而不是宗教式地分离。
04KV cache 变成系统边界
在 M2 里,KV cache 是 GPU 内的一组 block。到 M6,它变成三件事: 显存容量问题、跨实例缓存问题、跨 GPU 通信问题。 这就是 Mooncake 和 LMCache 这条线的关键。
Prefix cache:同前缀复用
vLLM 用 block hash 识别已经算过的 KV block。长文档、多轮 RAG、固定 system prompt 最容易赢。
Prefix-aware routing:把请求送回同一实例
如果 cache 只在本地 GPU,router 就要维护 locality。否则命中了逻辑前缀,却打到没有 KV 的 replica。
KV transfer:prefill 算完以后把 KV 交给 decode
需要 connector、传输元数据和高速互联。vLLM 当前把 disaggregated prefill 实现放在 KV transfer 相关模块下。
KV cache layer:CPU / SSD / remote cache
LMCache 把可复用 KV 从 engine 里抽出来,cache hit 时注入 KV,miss 时正常 prefill,并异步写回。
05投机解码:decode 阶段的并行化
decode 难的地方是自回归:不生成第 t 个 token,就不知道第 t+1 个 token。Speculative decoding 的技巧是: 让便宜 proposer 先猜多个 token,再用 target model 一次性验证。接受率高、draft 成本低时,ITL 会明显下降。
| 方法 | 适用场景 | 工程注意 | 读什么 |
|---|---|---|---|
| Draft model | 有一个足够便宜的小模型,且分布接近 target | draft 太贵或接受率低会倒亏 | vLLM speculative decoding docs |
| EAGLE / Medusa | 希望避免维护完整小模型,改用轻量 head / feature proposer | 需要模型适配或额外 head | EAGLE、Medusa、vLLM EAGLE |
| MTP | 模型本身训练了 multi-token prediction 能力 | 要确认 serving engine 支持对应模型路径 | DeepSeek-V3 technical report、vLLM MTP |
| N-gram / suffix | 代码、模板、重复文本,低峰期想便宜提速 | 收益较温和,但部署复杂度低 | vLLM n-gram speculation |
面试里不要只背"2-3x 加速"。更好的答案是:它把一次 target forward 产出的有效 token 数从 1 提高到 E[k], 但代价是 draft 计算、batch 扩张、KV 管理和拒绝 token 浪费。高 QPS 时,额外 workload 可能让系统更拥堵。
06量化和新模型结构:不是只省显存
FP8 W8A8、FP8 KV cache、INT4 weights、AWQ/GPTQ 这些常被讲成"模型变小"。 在 serving 系统里,它们的真实作用是改变容量、带宽、批大小和上下文长度的边界。
FP8 / KV cache quantization
KV cache 往往随上下文和并发线性增长。FP8 KV 能显著降低 KV footprint,让同样显存容纳更多 in-flight tokens 或更长 context。代价是硬件/attention backend 支持、scale 校准、准确率验证。
MoE / MLA / MTP
DeepSeek-V3 这类模型把 serving 问题改写了:MoE 带来 expert parallel 和 all-to-all,MLA 压缩 KV,MTP 给投机解码提供模型内能力。系统工程开始反过来被模型结构塑形。
07交互实验:给 workload 选优化栈
下面这个小模型不是严谨 benchmark,而是训练你的判断力。拖动参数,看瓶颈怎么从 prefill 转到 decode, 或从 GPU 计算转到 KV transfer / KV capacity。
08决策表:看到现象后该动哪里
| 现象 | 第一怀疑 | 优先动作 | 不要急着做 |
|---|---|---|---|
| TTFT 长,ITL 正常 | prefill 重、排队或 prefix cache 没命中 | 按 prompt length 分 bucket;开 APC;prefix-aware routing;长 prompt 试 disagg prefill | 盲目加 decode GPU |
| TTFT 正常,ITL p99 爆 | decode 被 prefill 插队或 decode pool 太满 | chunked prefill 或 P/D 分离;spec decode;看 time_per_output_token | 只看总 tokens/s |
| GPU cache usage 快满 | 上下文长、并发高、KV footprint 大 | FP8 KV;降低 max model len;更强 admission control;CPU/SSD cache tier | 只量化 weights |
| 分离后反而慢 | KV transfer tax 或 router 选错 | 测 KV bytes/request;按 topology 放置;短 prompt 走本地 prefill | 把所有请求强制 disagg |
| RAG 多次问同一文档仍很慢 | cache locality 没利用 | 固定文档 prefix;cache_salt 隔离租户;prefix-aware routing;LMCache | 只扩 GPU |
| MoE 模型吞吐差 | expert parallel 通信和负载均衡 | 看 all-to-all、EP/DP 配置、expert 热点;读 DeepEP / vLLM MoE kernel | 套 dense model 的经验 |
09你的 mini-vLLM v0.6:四个可交付方向
M6 不要求你重写生产 vLLM。要求是选一个方向,把 toy 系统升级成能解释取舍的实验平台。 简历上最值钱的不是"我也实现了 feature",而是"我能说清在什么 workload 下它赢,什么 workload 下它输"。
A. P/D 分离 simulator
- 把 mini scheduler 拆成 prefill queue 和 decode queue。
- 加 KV transfer cost 参数。
- 输出 TTFT/ITL/goodput 曲线。
B. Spec decode prototype
- 用 n-gram 或小 draft proposer 先做 lossless 验证。
- 记录 acceptance rate、expanded batch size、ITL。
- 写一段"什么时候倒亏"分析。
C. Prefix-cache-aware router
- 给 2-4 个 replica 做 prompt-prefix hash。
- 比较 round-robin、least-load、prefix-aware。
- 加 cache_salt 的租户隔离说明。
D. FP8/KV capacity benchmark
- 估算每 token KV bytes。
- 比较 fp16/bf16 KV 与 fp8 KV 的最大并发和上下文长度。
- 补一张 accuracy sanity check 表。
10最近前沿怎么读:一张研究地图
这不是新手要一口气读完的清单,而是你遇到具体问题时的索引。读法仍然保持本教材的三问: 它解决什么瓶颈?它引入什么新代价?它在 vLLM/production stack 里对应哪一层?
| 方向 | 代表材料 | 你要抓的主线 |
|---|---|---|
| P/D 分离与 goodput | DistServe、Splitwise、NVIDIA Dynamo disagg | prefill/decode 异构资源、双 SLO、KV transfer topology |
| KV-centric serving | Mooncake、LMCache、vLLM connectors | KV 从 engine 内部状态变成 cache/storage/communication layer |
| Prefix 与结构化调用 | SGLang、RadixAttention、vLLM prefix caching | 多轮、RAG、agent workflow 的共享前缀和路由 locality |
| Decode 加速 | vLLM speculative decoding、Medusa、EAGLE、MTP | 接受率、draft 成本、batch 扩张、lossless guarantee |
| 低精度 serving | vLLM FP8、Quantized KV Cache、AWQ/GPTQ | 显存容量、HBM 带宽、accuracy regression、backend 支持 |
| MoE / MLA / MTP | DeepSeek-V3 report、DeepEP | 模型结构改变 KV、通信和并行策略 |
11本页自检
Month 6 结束时这些应该全部 ✓
本章参考了 vLLM disaggregated prefill / prefix caching / speculative decoding / quantization 文档, DistServe (OSDI 2024)、Mooncake、SGLang、LMCache、NVIDIA Dynamo、DeepSeek-V3 和 DeepEP。 论文导读页会继续作为 15 篇核心阅读的索引。