第 26 讲 · 预填充与解码分离的 LLM 服务:DistServe 与 Dynamo · Serving with Disaggregated Prefill and Decoding

Large Language Model Systems · Lecture 26。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应 Maps to:CMU 11-868 / 11-968 Large Language Model Systems(Spring 2026,Lei Li),Lecture 26 · Mon 4/20 · Serving with Disaggregated Prefill-Decoding。主线 slides:Vikram Sharma Mailthody(NVIDIA Research): Inference at Scale: Opportunities and Challenges(llmsys-26-dynamo-vikram_mailthody.pdf,46 页);补充 slides:课表末尾 Hao Zhang(UCSD): Disaggregating Prefill and Decode for Goodput-optimized LLM Serving(llmsys-29-disaggregating_prefill_decode_hao_zhang.pdf,68 页)。 阅读材料:Zhong et al. (2024) DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving(OSDI);参考:Patel et al. (2024) Splitwise(ISCA)、Agrawal et al. (2024) Sarathi-Serve(OSDI);NVIDIA Dynamo 文档。 依据说明:两份 slides 分工明确。Hao Zhang 的 slides 讲 DistServe:服务 vs 推理、连续批处理的逐步演示、应用的 SLO(TTFT / TPOT)、吞吐 ≠ goodput、预填充计算受限 / 解码访存受限、同置造成的干扰与过度配置、并行策略的耦合、分离后 2P1D 达到 2 倍 goodput、两个核心问题(放置、通信)、高 / 低带宽集群的放置算法、KV 传输的代价、实测 2.0–4.48 倍、“连续批处理与分离并不矛盾”、分离的发展史、基于分离的系统(LMCache、DeepSeek-V3、Dynamo)。Vikram 的 slides 讲大规模推理:AI 工厂(xAI 的 10 万卡集群)、算力与电力趋势、推理与训练的不同、推理的工作流程与 KV 缓存、SGLang 的框架、SLO 与 goodput、帕累托曲线、规模化推理的挑战、Dynamo 的模块(分离部署、KV 感知路由、规划器、AIConfigurator、分层的 KV 内存管理、NIXL、Grove、容错)与开放问题。本讲义的”纸面 GPU”时间模型、同置 / 分块 / 分离三种部署的离散事件模拟器、goodput 的二分查找、放置算法的实现、在城市 LLaMA 上真的交接 KV、KV 路由 / 规划器 / 请求迁移的模拟,都是本讲义自己设计的,不代表课堂上讲了什么;工作负载的长度分布只取了 DistServe 图 7 的均值,形状是假设的。 配套代码 Code:code/lecture26/(5 个脚本 + disagg.py;03 号复用第 22 讲的前向与第 19 讲的模型;都在 30 秒以内) 预计阅读时间:3 小时(含运行代码)


0. 本讲导航 · How to read this lecture

0.1 学习目标 Learning goals

学完这一讲,你应该能够:

  1. 用算术强度解释为什么预填充是计算受限的、解码是访存受限的;算出两个阶段在一张 A100 上的大致时间。
  2. 定义 TTFT、TPOT、SLO 达成率与 goodput,说明为什么”吞吐高”不等于”goodput 高”。
  3. 说出同置部署的两个问题:预填充与解码的干扰、两个阶段资源与并行策略的耦合;以及分块预填充为什么只能缓解、不能消除干扰。
  4. 解释分离部署怎样工作(要交接什么状态)、怎样选 xPyD 的比例和每个阶段的并行策略,以及 KV 传输什么时候便宜、什么时候昂贵。
  5. 复述 DistServe 的两个放置算法(高带宽 / 低带宽集群)和它用的 M/D/1 排队分析。
  6. 说出 NVIDIA Dynamo 的主要部件(分离部署、KV 感知路由、规划器、配置搜索、分层 KV 内存、传输库、容错)各解决什么问题。

0.2 先修与本讲范围 Prerequisites & scope

默认你已经会 Assumed本讲只给直觉,后面再展开 Previewed only
连续批处理、RadixAttention、缓存感知的路由(第 22 讲)KV 缓存的压缩、分层存储与非前缀复用(第 27 讲)
PagedAttention、抢占与重算(第 24 讲)Mooncake 以 KV 为中心的架构(附加讲 A2)
张量并行与流水线并行(第 16 讲);屋顶线模型(第 4 讲)Kubernetes 上的调度细节(Grove)
排队论的基本概念(到达率、利用率、排队时间;前置讲 P4)推测解码、扩散式推理在服务中的位置

0.3 本讲地图 Map

§1  推理的规模:AI 工厂;推理与训练有什么不同                                        (slides)
§2  两个阶段、两种时延:预填充 vs 解码;TTFT、TPOT、goodput                         ← 代码 01
§3  同置的问题:干扰、生成卡顿、分块预填充、过度配置与耦合                          ← 代码 02
§4  分离部署:交接 KV;xPyD;三种应用上的 goodput                                  ← 代码 03
§5  放置:M/D/1 与并行策略;KV 传输;DistServe 的两个放置算法                        ← 代码 04
§6  NVIDIA Dynamo:路由、规划器、配置搜索、分层内存、传输、容错                      ← 代码 05
§7  分离的历史与基于分离的系统;开放问题
§8 小结   §9 常见误区   §10 练习   §11 延伸阅读   §12 下一讲预告

0.4 本讲的实验设置

没有 GPU 也能研究”在 GPU 集群上怎样部署”——DistServe 本身就是这么做的:它用一个模拟器估计每种放置的 SLO 达成率(论文报告模拟器与真实系统的达成率相差 < 2%),在模拟器里搜索放置。本讲义照着这个思路写了 disagg.py:

  • 时间模型:一次迭代的时间 = max(计算时间, 访存时间) ÷ 张量并行的加速比 + 固定开销。计算 = 2 × 参数量 × 新 token 数 + 注意力;访存 = 读一遍权重 + 读历史 KV + 写新 KV。规格用 A100 / H100 的公开标称值;“矩阵乘效率随 token 数上升”、“张量并行 2 路的加速比约 1.74”、“每次迭代 1 ms 固定开销”是假设(DistServe 附录 A 用实测拟合这些常数)。
  • 模拟器:同置(vLLM 式预填充优先、Sarathi 式分块预填充)、分离(n 个预填充实例 + k 个解码实例,各自的 tp / pp,中间按链路带宽传 KV)。每个请求记下第一个和最后一个 token 的时间,算 TTFT 与 TPOT。
  • 工作负载:泊松到达;三个应用的长度均值取自 DistServe 图 7(ShareGPT 输入 755 / 输出 200、HumanEval 171 / 98、LongBench 1738 / 91),分布形状是假设的;SLO 取自 DistServe 表 1。
  • goodput:二分查找”SLO 达成率 ≥ 90% 的最大到达率”,除以 GPU 数。

所以本讲义里的绝对数字(多少请求 / 秒)只说明趋势;每个脚本的观察里都会并列论文的实测数字。03 号脚本的第 1 部分是例外:它在第 19 讲的城市 LLaMA 上真的把 KV 从一个”实例”交给另一个。


1. 推理的规模 · Inference at scale

1.1 AI 工厂

Vikram 的 slides 从一个数字开始:xAI 的 Colossus 集群从空厂房到产出 token 用了不到 122 天,10 万张 GPU(正在扩到 20 万),功率超过 150 MW;4 个数据大厅、每个 2.5 万张卡,液冷机柜里每柜 64 张 GPU。用于训练 LLM 的算力每年增长约 4.2 倍(Epoch AI),而电力会成为 2030 年以后扩展训练的首要限制——这也是 GB200 NVL72 这类高密度机柜追求能效的原因。

这些”AI 工厂”产出的是 token。训练是一次性的大作业,推理则是每天都在发生、随用户规模增长的成本。slides 的一句话概括了本讲的立场:好模型 + 好系统 = 成功。

1.2 推理与训练有什么不同

slides 把两者对照着列出来:

训练推理
作业形态一个大作业,有中心协调者大量小作业,需要快速扩缩容
关心的事并行策略、容错、强 / 弱扩展、拓扑感知、数据预处理、优化器飞行中批处理(in-flight batching)、KV 缓存优化、量化、并行策略、用户自定义的调度
阶段前向 + 反向,形状固定预填充(P)+ 解码(D),两者性格迥异

推理的一个典型请求(slides 第 15–16 页的 CUDA 编程助手例子):系统提示(“你是 CUDA 专家……”)+ 用户提示 → 输出。系统提示在很多用户之间共享;输入可以长到 32K token,而且趋势是越来越长(写进更多”提示规则”能提高回答质量)。处理输入提示占了总时间的相当大一部分,甚至是主要部分。

计算上(slides 第 17–21 页,引自 PMPP 第 5 版):每层有 5 个矩阵乘;预填充时它们是矩阵 × 矩阵(GEMM);解码时每一步只给输入矩阵多加一行,借助 KV 缓存只算这一行——GEMM 退化成矩阵 × 向量(GEMV),从计算受限变成访存受限,同时 KV 缓存需要高效管理(PagedAttention、RadixAttention)。slides 用 SGLang 展示了一个推理框架的组成:API 服务器、分词器、调度器、去分词器、模型、带基数树的 KV 内存管理器——以及”用 Kubernetes 简单地多复制几份”这种最朴素的扩展方式。本讲就是要回答:只是复制,够吗?


2. 两个阶段、两种时延 · Prefill vs decode, TTFT vs TPOT

2.1 直觉:一个是”读整本书”,一个是”一个字一个字地写”

预填充一次处理整个提示:几百上千个 token 同时穿过模型,每个权重被复用几百上千次——这是 GPU 最擅长的大矩阵乘。解码每一步每个请求只处理 1 个 token:为了这 1 个 token,要把几十 GB 的权重和这个请求的全部 KV 从显存里读一遍——GPU 的算力几乎全闲着,时间都花在搬数据上。

01 号脚本用时间模型把这个直觉变成数字(OPT-13B,一张 A100):

预填充(1 个请求,输入 L)L = 161285122048
时间 ms16.927.774.0264.5
吞吐 token/s9444,6176,9227,744
算术强度 FLOPs/字节161285081986

A100 的屋脊点是 312 TFLOPS / 2.039 TB/s ≈ 153 FLOPs/字节(DistServe 附录 A 写的是 156)。预填充的算术强度随 L 线性增长,L ≈ 150 以后就越过屋脊点、变成计算受限;吞吐在 L ≥ 1024 时达到饱和值的 90%。DistServe 把这个”一个请求就能把 GPU 算满”的长度叫 L_m(论文里 13B 模型在 A100 上约 512):超过它,再往批里加请求只会让每个请求都等更久。所以预填充实例的批很小,优化目标是 TTFT。

解码(上下文 512,批大小 B)B = 116128256
一步的时间 ms17.221.149.982.9
吞吐 token/s587602,5643,088
算术强度1.012.942.450.6

B = 1 时 17 ms 几乎全花在读 26 GB 权重上,吞吐只有 58 token/s(2048-token 预填充的 0.8%)。批越大越划算:B = 128 时吞吐是 B = 1 的 44 倍,每步时间只多 2.9 倍。但批不能无限大——批里所有请求的 KV 每步都要读一遍,算术强度最多只到 50 左右;而且一张卡放下权重后只剩约 59,000 个 token 的 KV(OPT-13B 每个 token 800 KiB),上下文 512 时最多约 115 个请求。解码必须攒大批,批的上限是显存。

为什么这一节重要? 两个阶段”想要”的东西相反:预填充要小批、快速完成;解码要大批、显存越多越好。下面所有的设计都从这个矛盾出发。

2.2 两种时延与 SLO

一个请求的时间线:到达 → 排队 → 预填充(产生第一个 token)→ 若干个解码步(每步一个 token)→ 结束。于是有两个时延指标:

  • TTFT(time to first token,首 token 时延):从到达到第一个 token。由预填充(和它前面的排队)决定。
  • TPOT(time per output token,每个输出 token 的时延;也叫 TBT / ITL,token 间时延):除第一个 token 外,平均每个 token 的时间 = (最后一个 token 的时间 − 第一个 token 的时间) / (输出长度 − 1)。由解码决定。
  • 端到端时延 = TTFT + TPOT × (输出长度 − 1)。01 号脚本:一个输入 755、输出 200 的聊天请求在空闲 GPU 上 ≈ 0.104 + 0.0307 × 199 ≈ 6.2 秒。

不同应用对两者的要求不同(DistServe 表 1;Hao Zhang slides 第 30 页):

应用模型TTFT SLOTPOT SLO为什么
聊天OPT-13B / 66B / 175B0.25 / 2.5 / 4.0 秒0.1 / 0.15 / 0.2 秒首 token 要快;TPOT 只要快过人的阅读速度(每分钟约 250 个词)
代码补全OPT-66B0.125 秒0.2 秒实时的编程助手,两个都严
摘要OPT-66B15 秒0.15 秒能等首 token,但要求生成快

slides 的说法:聊天的 TPOT 按人的阅读速度定(P99 250 ms);给程序读的数据生成要严得多(P99 35 ms)。

2.3 吞吐 ≠ goodput

吞吐(每秒完成多少请求)是”每个请求花多少钱”的代理指标(slides 引用黄仁勋 GTC’25 的说法)。但用户在乎的是满足时延要求的请求。goodput = 每秒完成的、满足 SLO 的请求数。DistServe 的精确定义:SLO 达成率 ≥ 90% 的前提下系统能承受的最大到达率;除以 GPU 数就是 per-GPU goodput,它直接对应”每个合格请求的成本”。

01 号脚本第 4 部分(OPT-13B 聊天,一张 A100,vLLM 式同置):

到达率 请求/秒0.512468
吞吐 请求/秒0.561.092.103.333.834.11
SLO 达成率92%90%88%71%5%1%
P90 TTFT 秒0.220.250.260.4637.781.0

到达率越高,批越大,吞吐一路上升;可满足 SLO 的比例在到达率 4 以后断崖式下跌——队列越排越长,TTFT 爆掉。slides 的例子:一个”高吞吐”系统吞吐 10 rps,goodput 只有 3 rps。以吞吐为目标优化的系统,可能 goodput 很差。


3. 同置的问题 · What goes wrong with colocation

3.1 连续批处理回顾

Hao Zhang 的 slides 先用十几页逐步演示了连续批处理(ORCA,第 22 讲):静态批处理要等批里所有请求都结束,提前结束的请求空占位置、新请求进不来;连续批处理每一步都让结束的请求退出、新请求加入。它把吞吐提高了约 10 倍(相对静态批处理),已经是所有推理引擎的标配。

问题在于:新请求”加入”意味着它的预填充和其他请求的解码被放进同一次迭代(或者轮流占用同一块 GPU)。这就是同置(colocation)。

3.2 干扰:一次迭代被更慢的那部分拖住

02 号脚本第 1 部分复现了 DistServe 图 2 的形状(OPT-13B,一张 A100):

输入长度解码批只有解码 ms+ 1 个预填充 ms解码变慢预填充变慢
1283219.031.61.66×1.14×
12812827.843.01.55×1.55×
10243233.4140.44.20×1.03×
102412882.8152.21.84×1.12×

一个 1024-token 的预填充混进 32 人的解码批,这一步从 33 ms 变成 140 ms——批里每个请求的这个 token 都晚到了 4 倍多。反过来,批越大、上下文越长,预填充也被拖慢。一次迭代的时间由更慢的那部分决定,两种负载谁都没法单独优化。

“那就别放在一个迭代里,轮流跑?“——vLLM 当时的默认调度就是预填充优先:有新请求就先跑一个只含预填充的迭代。结果是正在解码的请求整体停下来等。DistServe §2.3 指出:分开调度也解决不了,解码要排在预填充后面、预填充也要排在解码后面;无论优先哪个,另一个的时延都会受损。

3.3 生成卡顿

用户的直观感受是什么?02 号脚本第 3 部分记录了每个输出 token 的时间(OPT-13B 聊天,到达率 1.5):

部署TBT P50 msTBT P99 ms最长 ms超过 P50 三倍的比例
同置:预填充优先(vLLM)20.7146.14472.8%
同置:分块预填充,块 512(Sarathi)20.575.1774.2%
分离:2P1D20.023.4470.0%

预填充优先时,输出偶尔会卡住近半秒(一次塞了几千个 token 的预填充迭代)。Sarathi-Serve 管这叫 generation stall(生成卡顿)。

3.4 分块预填充:缓解,而非消除

Sarathi-Serve(Agrawal et al., OSDI’24)和 DeepSpeed-MII 的办法:把长提示切成块,每次迭代给一个固定的 token 预算,先放所有正在解码的请求,剩下的预算切一块提示来预填充(“捎带”,piggyback)。解码从此不会停(stall-free),上表的 P99 从 146 ms 降到 75 ms。Sarathi-Serve 报告在 Mistral-7B 上比 vLLM 多服务 2.6 倍、Falcon-180B 上 5.6 倍。

但 DistServe 指出它有两个本质的代价(02 号脚本第 4 部分全都看得到):

  1. TTFT 变差:块小了,一个提示要好几次迭代才做完;块大了,捎带的空间就少了,又回到卡顿。没有一个块大小能两全。
  2. 重复读 KV:第 k 块要把前 k − 1 块的 KV 再读一遍,总共 O(N²) 块。2048-token 的提示切成 256 的块,要重复读 7,168 个 token 的 KV(提示长度的 3.5 倍)。
工作负载调度P90 TTFT 秒P90 TPOT msgoodput 请求/秒
聊天(OPT-13B)不分块0.25251.60
分块 512 / 20480.30 / 0.2524 / 240.26 / 1.23
摘要(OPT-66B,tp 4)不分块0.911111.16
分块 256 / 512 / 20481.50 / 1.08 / 0.8975 / 86 / 981.79 / 2.10 / 1.29

聊天的 TTFT 只有 0.25 秒,分块的额外开销直接让长提示超标——分块反而更差;摘要的 TTFT 宽松、TPOT 严,分块正好对症,goodput 提高 1.8 倍。这与 DistServe 的实测吻合:DeepSpeed-MII 在 13B 聊天上不如 vLLM,在长输入的摘要上比 vLLM 好。分块只是在 TTFT 与 TPOT 之间换来换去,干扰本身还在。

3.5 过度配置与耦合

干扰的直接后果是过度配置(Hao Zhang slides 第 39 页的 x1 → x4):为了同时满足两个 SLO,只好多买 GPU、让每张卡都轻载。

第二个问题更隐蔽:并行策略的耦合(slides 第 40 页)。预填充的 TTFT 紧,喜欢张量并行(缩短单个请求的执行时间);解码的 TPOT 松一些但要大批,喜欢流水线并行或数据并行(扩大批和吞吐)。同置时两个阶段只能共用一种切法,只能迁就更严格的那个。

02 号脚本第 2 部分复现了 DistServe 图 1 的论证(OPT-13B,输入 512、输出 64,一张 A100):同置时 goodput 4.74 请求 / 秒;同一张卡只做预填充能撑 10.89,只做解码能撑 30.85。两个阶段单独都比合在一起强得多。


4. 分离部署 · Disaggregating prefill and decode

4.1 想法

既然两个阶段合在一起互相拖累,就把它们放到不同的 GPU 上:预填充实例只做预填充,算完把 KV 缓存交给解码实例;解码实例只做解码(连续批处理照旧)。这立刻带来两个好处(Hao Zhang slides 第 44 页):

  • 干扰消失:解码实例上没有预填充(上表 2P1D 的 P99 TBT 只有 23 ms)。
  • 问题一分为二:预填充实例只管 TTFT,解码实例只管 TPOT;每个阶段各选最合适的并行策略和资源量。

“实例”(instance)指持有一份完整模型权重的一组 GPU。分离后两种实例各有一份权重;因为解码的 GPU 利用率低,通常让多个预填充实例对应一个解码实例,把解码的批攒大。

代价也有两个:KV 缓存的传输;以及”每张 GPU 的 goodput”变成一个牵涉工作负载、SLO、并行策略、资源配比、网络带宽的优化问题(slides 第 48 页)。§5 回答它们。

4.2 要交接的到底是什么?

03 号脚本第 1 部分在第 19 讲的城市 LLaMA 上真的做了一遍:预填充”实例”算出 KV 和第一个 token,用 torch.save 序列化成字节(模拟网络传输),解码”实例”(另一份权重)反序列化后接着生成。

请求提示长度KV 字节(公式)传输字节 FP32传输字节 FP16贪心:FP32 / FP16 交接采样:带 RNG 状态
03367,58469,22535,433相同 / 相同相同
23979,87281,51341,577相同 / 相同相同

交接之后的输出与”一个实例从头做到尾”逐 token 相同:KV 缓存(加上第一个 token)就是预填充留给解码的全部状态;采样时还要带上这个请求的随机数生成器状态。用 FP16 传,字节数减半,输出也没变——KV 可以有损地传输和存储,这是第 27 讲的出发点。

真实系统里 KV 不经过序列化:DistServe 用 NCCL 跨节点传、用异步 cudaMemcpy 在节点内传,不阻塞 GPU 计算;而且是解码实例来”拉”(pull)——预填充实例算完就把 KV 留在自己的显存里当缓冲区,解码实例有空位时再取。这样突发流量不会把解码实例的显存冲爆,两种实例各按自己的节奏工作。

4.3 2P1D:每张 GPU 两倍的 goodput

DistServe 图 1 的论证(Hao Zhang slides 第 45–47 页):既然一张卡只做预填充能撑 5.6 rps、只做解码能撑 10 rps,那么 2 张卡做预填充 + 1 张卡做解码就能撑约 10 rps,每张 GPU 3.3 rps——是同置(1.6 rps)的 2.1 倍。最简单的分离就能让每张 GPU 的 goodput 翻倍。

02 号脚本的纸面模型:同置 4.74,2P1D 实际模拟 24.21 请求 / 秒、每张 GPU 8.07,是同置的 1.7 倍(2P1D 比 2 × 单卡预填充还高一点:两个预填充实例共用一个队列、谁空谁接,排队更短)。

比例怎么选?03 号脚本第 2 部分固定 6 张卡、每个实例 1 张卡:

比例1P5D2P4D3P3D4P2D5P1D
输入 512 / 输出 6410.8924.2138.5651.1530.84
聊天1.888.5417.4015.507.38

最优比例取决于两个阶段的负担和各自的 SLO——没有通用的比例。比例选错,多出来的 GPU 就闲着;流量的组成变了,最优比例也跟着变(§6.3 的规划器)。

4.4 三种应用上的结果

03 号脚本第 3 部分在三种应用上比较三种部署(每张 GPU 的 goodput,请求 / 秒;“分离”一列是按算法 1 选配置、整体模拟 n 个预填充实例 + k 个解码实例、两个 SLO 同时达标 ≥ 90% 的结果):

应用 / 模型同置(vLLM)分块(最好的块)分离分离的放置vs 同置
聊天 / OPT-13B1.601.234.132×P(tp2, pp4) + 3×D(tp2, pp2)2.6×
聊天 / OPT-66B0.680.840.951×P(tp1, pp8) + 1×D(tp4, pp2)1.4×
代码补全 / OPT-66B0.590.651.844×P(tp8, pp1) + 1×D(tp4, pp2)3.1×
摘要 / OPT-66B0.290.530.692×P(tp1, pp8) + 1×D(tp4, pp2)2.4×

DistServe 的实测(4 个节点 × 8 张 A100):比 vLLM 高 2.0–4.6 倍(聊天)、5.7 倍(代码补全)、4.3 倍(摘要),比 DeepSpeed-MII 高 1.6–7.4 倍;Hao Zhang 的 slides 给的汇总是 2.0–4.48 倍。纸面模型的倍数小一些,但三点一致:分离最好;两个阶段选了完全不同的并行策略(代码补全的 TTFT 只有 0.125 秒,预填充选了张量并行 8 路;摘要的 TTFT 宽松,预填充选了流水线 8 段);分块在长输入上帮助最大、在 TTFT 很紧时帮倒忙。

DistServe 的另一种比法是 SLO scale:固定流量,看系统能承受多严格的 SLO。03 号脚本第 4 部分:每张 GPU 1 请求 / 秒时,同置只能承受表 1 的 SLO(0.99 倍),分离能把两个 SLO 同时收紧到 0.59 倍(论文:比 vLLM 严 1.8–3.2 倍,摘要上 12.6 倍)。省 GPU 和给用户更快的响应,是同一枚硬币的两面。

4.5 来回折腾?

Hao Zhang slides 第 57 页提了一个好问题:连续批处理把预填充和解码合到一起,分离又把它们拆开——是不是在来回折腾?不是。连续批处理的目标是 GPU 利用率,也就是吞吐;分离的目标是满足 SLO 的吞吐,也就是 goodput。而且连续批处理的两条关键洞见在分离后仍然成立:注意力与 MLP 分开批处理(选择性批处理);结束的请求尽快退出、新请求尽快加入(解码实例内部仍是连续批处理)。

DistServe 自己也说了分离不适合的场景(§7):只追求吞吐的离线任务(没有时延要求,分块预填充能把每个迭代都填到计算饱和);资源很少(一两张卡,没有拆分的空间)。


5. 放置:并行策略与 KV 传输 · Placement

5.1 预填充实例是一个 M/D/1 队列

分离后,预填充实例的行为非常规整:输入长度相同时,每个请求的执行时间是确定的 D;一个请求就能把 GPU 算满,所以一个一个按到达顺序做。泊松到达 + 确定服务时间 + 一个服务台 = M/D/1 队列,平均 TTFT 有闭式解(DistServe 式 (1)):

Avg TTFT=D+RD22(1−RD)\text{Avg TTFT} = D + \frac{R D^2}{2(1 - R D)}

第一项是执行时间,第二项是排队时间(R 是到达率,要求 RD < 1)。2 张卡时有两种用法:

  • 流水线并行 2 段(inter-op):单个请求的时间不变(≈ D),但每段只占 D/2,“服务台”每 D/2 就能接下一个:Avg TTFT = D + R D² / (4(2 − R D))(式 (2))。
  • 张量并行 2 路(intra-op):单个请求变快到 D/K(K < 2 是通信损耗后的加速比),但仍是一个服务台:Avg TTFT = D/K + R D² / (2K(K − R D))(式 (3))。

04 号脚本第 1 部分(OPT-66B,2 张 A100,输入都是 512):流水线 D = 371 ms,张量 215 ms(K = 1.73)。

到达率0.512344.55
流水线:模拟 / 式 (2)0.381 / 0.3810.391 / 0.3920.423 / 0.4260.475 / 0.4880.593 / 0.6380.758 / 0.8411.30 / 1.57
张量:模拟 / 式 (3)0.228 / 0.2270.243 / 0.2440.289 / 0.2950.388 / 0.4080.749 / 0.8641.96 / 3.2127.4 / ∞

低到达率时排队很少,执行快的张量并行赢;到达率约 4 以后,排队主导,容量更大的流水线并行赢(张量并行最多撑 1/0.215 = 4.66 请求 / 秒,流水线 2/0.371 = 5.39)——这正是 DistServe 图 4a。结论:预填充的并行策略取决于到达率和 TTFT 的 SLO(SLO 越紧越偏向张量并行;K 越小,张量并行越不划算),需要搜索而不是一条规则。

解码实例的分析类似(DistServe §3.2、图 5):张量并行降低每一步的时间,但收益递减;流水线并行几乎线性地提高吞吐。TPOT 紧时必须用张量并行,此外用流水线并行扩吞吐。模型放得进一张卡时,复制(数据并行)也是一个选项:N 个副本把 R 换成 R/N。

5.2 KV 传输贵不贵?

04 号脚本第 2 部分:

模型每个 token 的 KV512-token 请求10 请求/秒 要的带宽
OPT-13B(多头注意力)0.78 MiB0.39 GiB34 Gb/s
OPT-66B2.25 MiB1.12 GiB97 Gb/s
OPT-175B4.50 MiB2.25 GiB193 Gb/s
LLaMA-3.1-70B(GQA,8 组 KV)0.31 MiB0.16 GiB13 Gb/s

DistServe §3.3 的例子:OPT-66B 一个 512-token 请求的 KV 约 1.13 GiB,10 请求 / 秒就要约 90 Gb/s。OPT 系列是多头注意力,KV 特别大——DistServe 特意选它”给传输施加足够的压力”;GQA / MQA 的现代模型压力小一个数量级。

传一个 OPT-66B 的 512-token 请求:

链路单方向带宽时间相当于几个解码步(tp 4、批 32,约 43 ms)
NVLink(A100 节点内)300 GB/s4 ms0.09
InfiniBand 800 Gb/s100 GB/s12 ms0.28
PCIe 4.0 x1632 GB/s38 ms0.87
以太网 25 Gb/s3.1 GB/s387 ms8.9

在节点内的 NVLink 或现代的 InfiniBand 上,传输比一个解码步还短,可以忽略(slides 第 55 页:即使 175B 模型走 PCIe,传输时间也小于一个解码步)。但如果只有 25 Gb/s 的跨节点网络,一条链路每秒只能传一两个请求的 KV。另外,长上下文时比例反而变好:KV 随长度线性增长,预填充的计算随长度超线性增长(DistServe §7)。

5.3 算法 1:高带宽集群

带宽足够时,两个阶段互不牵制,可以分开优化再复制(DistServe 算法 1):

对每个 intra-op(张量并行度)∈ {1, …, M},每个 inter-op(流水线段数):
    如果模型切开后放得下:
        用模拟器 + 二分查找求"只看 TTFT 的 goodput",更新每张 GPU 最好的预填充配置
        用模拟器 + 二分查找求"只看 TPOT 的 goodput",更新每张 GPU 最好的解码配置
n = ⌈R / 预填充配置的 goodput⌉,m = ⌈R / 解码配置的 goodput⌉

复杂度 O(N·M²)(N 是一个实例最多跨几个节点,M 是每个节点的卡数)。模拟器要知道工作负载:DistServe 从历史请求里拟合长度分布、重新采样,用分析式的时延模型(附录 A:预填充 T = C₁(4th² + 2thm) + C₂·3ht₂/b + C₃,解码 T = C₄(4h² + 2hm) + C₅·3ht,常数靠测量拟合)计时。

04 号脚本第 3 部分(聊天,OPT-66B):

预填充配置每张 GPU解码配置每张 GPU
tp 1, pp 81.99tp 4, pp 21.92
tp 1, pp 41.84tp 8, pp 11.78
tp 2, pp 41.75tp 2, pp 41.64
……
tp 8, pp 10.93tp 1, pp 20.17

两个阶段的最优配置截然不同:聊天的 TTFT(2.5 秒)宽松,预填充偏爱流水线并行(吞吐高);解码用张量并行压低每一步、用流水线扩大批。最好的解码配置是最差的 11.6 倍——选错配置的代价很大。按 R = 10 复制(各 1 个实例、16 张卡),整体模拟的达成率 100%:两个阶段的 SLO 各自满足,拼起来不会互相破坏。

5.4 算法 2:低带宽集群

DistServe 的测试床跨节点只有 25 Gb/s。04 号脚本第 4 部分:同样的放置,KV 从 800 Gb/s 换成 25 Gb/s,每张 GPU 的 goodput 从 0.952 掉到 0.105——每个聊天请求平均约 1.69 GB 的 KV,一条 25 Gb/s 的链路每秒只能传约 1.8 个,传输排成长队。

算法 2 的关键观察:KV 只在”对应的层”之间传。把预填充和解码实例都按流水线切成段,同一段的预填充和解码放在同一个节点里,KV 就只走节点内的 NVLink:

对每个 inter-op ∈ {1, …, N}(每对实例跨几个节点):
    枚举节点内的配置 P_p(预填充段的张量并行)、P_d(解码段的张量并行),要求 P_p + P_d ≤ M
    整体模拟这一对实例的 goodput,按每张 GPU 取最好
按流量复制

代价是搜索空间变小。纸面模型里它找到”每对跨 4 个节点、每个节点 P tp 2 + D tp 2”,每张 GPU 0.820(高带宽时算法 1 是 0.952;DistServe 的消融实验也是 DistServe-High > DistServe-Low)。

对 OPT-175B(350 GB),一个节点(640 GB)连一对实例都放不下,只能切段。04 号脚本第 5 部分的纸面模型选了”跨 4 个节点、每个节点 P tp 4 + D tp 4”;DistServe 在真实测试床上找到的是预填充 inter-op 3、intra-op 3,解码 inter-op 3、intra-op 4(每个节点 3 + 4 = 7 张卡)——tp = 3 这种非 2 的幂的配置人很难想到,搜索能找到。实测 OPT-175B 的 KV 传输只占总时延的 0.1% 以下,95% 的请求传输时间 < 30 ms。

5.5 运行时的调度

放置定下来之后,DistServe 的在线调度很简单(§4.3):请求先交给队列最短的预填充实例,FCFS;预填充批的总长凑到 L_m 左右(短提示拼批,长提示单独跑),减少流水线气泡;然后交给负载最轻的解码实例。KV 用”拉”的方式传。流量模式变了(平均长度、到达率),就重新运行放置算法(几秒到几分钟)并重新加载权重(几分钟)——比真实流量的小时级变化快得多。

DistServe 没做的两件事——抢占(FCFS 的”护航效应”:长请求挡住短请求)和容错(一个解码实例挂了会连累所有向它供货的预填充实例)——正是 Dynamo 这类生产系统要补上的。


6. NVIDIA Dynamo · Distributed inference at scale

6.1 规模化推理的挑战

Vikram 的 slides 列出了在规模上做推理要面对的问题:

  • 为了达到 SLA,要按请求调整并行策略;输入 / 输出长度(ISL / OSL)各不相同,有多轮对话、有智能体发起的调用;
  • 异构硬件(不同代、不同平台);多个模型同时服务;容错;
  • 优化目标是 AI 工厂的总拥有成本(TCO):goodput、功耗、KV 缓存命中率……

2025 年的部署规模:输入 100 万 token 以上(RAG、视频理解、代码),输出越来越长(推理模型、智能体工作流),模型 1000 亿到 1 万亿参数。吞吐与时延之间是一条帕累托曲线(slides 引用 SemiAnalysis 的 InferenceMAX 基准):后训练(RL 的生成)要高吞吐,自动补全要低时延,同一个系统要能在曲线上移动。

Dynamo 是 NVIDIA 的开源分布式推理框架(GTC 2025 发布),定位是”推理引擎之上”的一层:支持 vLLM、SGLang、TensorRT-LLM 作为后端;模块化、各部件独立扩展。下面逐个看它的部件。

6.2 分离部署与 KV 感知的路由

分离部署是 Dynamo 的一个特性:预填充和解码各自扩展、各自选并行策略(slides 第 34–36 页,图取自 DistServe 与 Splitwise)。

KV 感知的路由器:多个工作节点各有自己的前缀缓存(第 22 讲的 RadixAttention),请求该发给谁?发给缓存命中最多的节点,预填充最省;但热门的前缀会让少数节点过载。Dynamo 的路由器对每个节点算一个代价——“还要算多少块”乘以权重,加上”节点当前的负载(活跃的块数)“——选代价最小的。

05 号脚本第 1 部分(8 个节点 × 一张 H100,LLaMA-3-8B;600 个多轮会话、6 个应用各有 2,048 token 的系统提示;每秒 120 个请求):

路由策略命中率平均 TTFTP90 TTFT最忙节点 / 平均
轮询56%192 ms458 ms1.04
最空闲56%92 ms175 ms1.00
KV 路由,权重 1(= 预计 TTFT 最短)87%24 ms39 ms1.68
只看命中(权重 1000)87%66 ms165 ms2.59

不看缓存的路由把同一个会话的各轮打散到不同节点,每个节点都要装下所有会话——装不下,基本只命中共享的系统提示。KV 路由让会话”粘”在一个节点上,8 个节点的缓存合起来装下整个工作集。但只看命中会让热门会话挤在少数节点上。权重就是在命中与均衡之间取舍。slides 引用的 Baseten 案例(Qwen3-Coder 480B):KV 感知路由让 TTFT 快 2 倍、TPOT 快 1.5 倍、吞吐高 1.6 倍。

6.3 规划器与配置搜索

规划器(Planner):LLM 的流量变化很快,规划器按 SLA(TTFT、TPOT)实时增减预填充 / 解码节点。它由三部分组成:离线剖析(每种配置在 SLA 下能撑多少)、负载预测(ARIMA、Prophet 等)、插值器(把预测的负载换算成节点数)。slides 引用阿里云的数据:TTFT 降低 80%,同时少用 5% 的 GPU。

05 号脚本第 2 部分用一个流体模型演示(LLaMA-3-8B,6 小时的流量,有周期起伏、一次 2 倍的突发、一段”输入变长一倍”的时期;新节点要 3 分钟才能用上):

做法GPU·时超出能力的请求预填充节点解码节点
按峰值静态配置1200.00%137
按平均静态配置4818.60%53
规划器:最近 5 分钟的平均521.73%2–141–7
规划器:趋势外推513.32%1–141–7

规划器只用了峰值配置 43% 的 GPU·时;违反主要来自突发开始后的 20 多分钟(1.51%)——预测跟不上、新节点还在加载。趋势外推反而更差:它把最近一分钟的变化放大好几倍往前推,在拐点上过冲和欠配——预测器本身也要调。输入变长的那一小时,预填充 / 解码节点的比例从 1.98 升到 3.45:两个阶段独立伸缩,这是分离部署的又一个好处。

AIConfigurator:离线的配置搜索,与 DistServe 的放置算法同一思路——给定模型、GPU 数、硬件、输入 / 输出长度和 TTFT / TPOT 要求(slides 的例子:Qwen3-32B、32 张 H200、ISL 4000、OSL 500、TTFT 300 ms、TPOT 10 ms),在笔记本上 1 分钟内找出最佳的分离配置并生成部署文件,代替在 GPU 上测两天。04 号脚本的搜索都在几秒内完成。

6.4 分层的 KV 内存与传输

KV 块管理器(KVBM)利用数据中心里所有的存储层级:G1 显存、G2 主机内存、G3 本地 SSD、G4 网络存储。把 KV 卸载到下层,命中时再取回——slides:分离部署 + KV 卸载让 TTFT 快 2.2 倍;适用于多轮对话、代码生成、智能体调用、生成式推荐。这正是第 27 讲(LMCache)的主题。

NIXL(NVIDIA Inference Xfer Library):统一的数据传输库。上层(“北向”)给推理框架一套跨节点、跨存储层级的传输接口;下层(“南向”)插接各种后端——UCX、Mooncake 的传输引擎、GPUDirect Storage、POSIX、3FS 等,自动选最好的。

Grove:Kubernetes 上按拓扑优化的调度。分离部署的一个”服务”由多种角色组成(预填充组、解码组、路由器……),各有副本数和最小副本数,需要整体地、按 NVLink / 网络拓扑放置和伸缩——普通的 Deployment / LeaderWorkerSet 表达不了。

6.5 容错

Dynamo 提供三种机制(slides 第 41 页):高可用(路由器的状态共享,挂了自动重启)、请求取消(用户断开就停止计算)、请求迁移(在 token 粒度上迁移已生成的部分回答)。

05 号脚本第 3 部分(LLaMA-3.1-70B,8 × H100;输入 2000):解码节点在生成了 g 个 token 后故障——

g让客户端重试:追上进度要等迁移:停顿迁移:重新预填充的长度
501.17 秒0.117 秒1.02×
2004.34 秒0.125 秒1.10×
80017.0 秒0.158 秒1.40×

迁移时,前端已经把生成的 token 流给了用户;把”提示 + 已生成的 g 个 token”作为一个新的预填充发给另一个节点,从第 g + 1 个 token 接着生成,代价只是一次稍长的预填充。这和第 24 讲的”抢占后重算”是同一个道理:KV 可以从 token 重新算出来,token 才是真正要保存的状态。


7. 分离的历史与基于分离的系统 · History and systems built on disaggregation

Hao Zhang 讲了一段”分离的趣史”(slides 第 58–59 页):

  • 2023 年底:DistServe 在 UCSD 发表并开源;同期有微软的 Splitwise(未开源)。Splitwise 的角度是硬件:解码不需要最新 GPU 的算力,可以放在更便宜、更省电的 GPU 上(论文:同样成本下吞吐高 1.4 倍、成本低 20%,或同样的功耗和成本下吞吐高 2.35 倍)。
  • 2024 年:开源社区接入得比连续批处理、PagedAttention 慢——小规模上看不出显著收益。但它悄悄地成了大公司大规模部署的首选架构(字节跳动、Google 等)。
  • 2025 年:DeepSeek-V3 用预填充 / 解码分离,两个阶段用不同的并行:预填充 4 路张量并行(带序列并行)+ 8 路数据并行、MoE 32 路专家并行(最小部署单元 32 张卡);解码 4 路张量并行 + 80 路数据并行、MoE 320 路专家并行、冗余专家(最小单元 320 张卡)。同年,NVIDIA 在 GTC 主题演讲里发布 Dynamo。

基于分离的系统:LMCache / CacheGen(KV 可以有损地存储、压缩后在网络上传输——第 27 讲)、DeepSeek-V3 的服务、Dynamo;以及以 KV 缓存为中心的 Mooncake(Kimi 的服务平台,附加讲 A2)。

开放问题(Vikram 的 slides):大规模的异构模型部署几乎没人研究过;智能体任务需要多个模型紧密协作;KV 缓存与数据传输的效率;规模化推理缺乏容错和性能测量工具(AIPerf 是一个尝试;智能体的性能建模、多模态的性能刻画、推理的故障注入框架都还空白);推测解码、扩散式推理模型在服务中的位置;企业级 RAG + 缓存增强生成(CAG);以及——模型变得这么快,软件栈怎样跟上?


8. 小结 · Summary

  1. 两个阶段性格相反:预填充计算受限(算术强度随提示长度增长,一个几百 token 的提示就能算满 GPU),要小批、快速完成;解码访存受限(每步读一遍权重和全部 KV),要大批,批的上限是显存。
  2. 两种时延、一个目标:TTFT 由预填充决定,TPOT 由解码决定;goodput = SLO 达成率 ≥ 90% 时的最大到达率,per-GPU goodput 对应每个合格请求的成本。吞吐 ≠ goodput。
  3. 同置的两个问题:干扰(一次迭代被更慢的那部分拖住、生成卡顿)和耦合(两个阶段共用资源与并行策略)。结果是过度配置。分块预填充只是在 TTFT 与 TPOT 之间交换,消除不了干扰,还带来 O(N²) 的 KV 重复读。
  4. 分离:预填充实例算完把 KV(+ 第一个 token)交给解码实例。干扰消失,两个阶段各自优化;代价是 KV 传输和一个更复杂的放置问题。最简单的 2P1D 就能让每张 GPU 的 goodput 翻倍(DistServe 实测 2.0–4.6 倍、最多 7.4 倍)。
  5. 放置:预填充实例 ≈ M/D/1 队列,低负载偏爱张量并行、高负载偏爱流水线并行;KV 传输在 NVLink / 高速 InfiniBand 上可以忽略,在低带宽网络上必须把同一段的预填充和解码放进同一个节点(算法 2)。搜索靠模拟器,几秒到几分钟。
  6. Dynamo 把这些做成生产系统:分离部署、KV 感知路由(命中与负载的加权)、按 SLA 伸缩的规划器、离线配置搜索、分层 KV 内存(G1–G4)、统一的传输库 NIXL、拓扑感知的调度、请求迁移等容错机制。

9. 常见误区 · Common pitfalls

  1. “吞吐最高的系统就是最好的服务系统。” 用户在乎的是满足 SLO 的请求;吞吐高的系统可能大部分请求都超时(01 号脚本:到达率 8 时吞吐 4.1 请求 / 秒,达成率 1%)。
  2. “分块预填充解决了预填充与解码的干扰。” 它把大的卡顿摊成小的、经常的减速,并让 TTFT 变差;TTFT 很紧时甚至比不分块更差(02 号脚本)。
  3. “分离部署要多传一份 KV,一定更慢。” 在节点内 NVLink 或现代 InfiniBand 上,传一个请求的 KV 比一个解码步还短;而消除干扰、各选并行策略带来的收益大得多。
  4. “分离后,预填充和解码各用一半 GPU 就好。” 最优比例取决于输入 / 输出长度和两个 SLO(03 号脚本:短输出 4P2D,聊天 3P3D),而且会随流量变化——这就是规划器的作用。
  5. “张量并行总是比流水线并行好(延迟更低)。” 对预填充实例,高到达率时排队主导,容量更大的流水线并行反而 TTFT 更低(04 号脚本、DistServe 图 4)。
  6. “分离只是一种部署技巧,跟模型无关。” KV 的大小决定了传输压力:多头注意力的 OPT-175B 每个 token 4.5 MiB,GQA 的 LLaMA-3.1-70B 只有 0.31 MiB;MLA 更小。模型结构和服务架构是一起演化的。
  7. “KV 感知路由就是把请求发给命中最多的节点。” 只看命中会让热门前缀压垮少数节点(05 号脚本:P90 TTFT 165 ms vs 39 ms)。
  8. “节点故障时,正在生成的请求只能重来。” 已生成的 token 在前端;把它们和提示一起作为一次预填充迁移到别的节点,停顿只有一次预填充的时间。

10. 练习 · Exercises

  1. 用屋脊点解释:为什么一个 13B 模型在 A100 上,预填充约 150 个 token 以后就是计算受限的,而解码批大小 256 时仍是访存受限的?
  2. 一个请求输入 1000、输出 300 个 token,TTFT 0.2 秒、TPOT 40 ms。端到端时延是多少?如果 TPOT 的 SLO 是 50 ms,而有 5% 的解码步因为插入预填充变成 300 ms,这个请求的 TPOT 还达标吗?
  3. 已知一张卡只做预填充时 goodput 为 6 rps,只做解码时 15 rps。用 xPyD 的整数实例数,每张 GPU 的最佳 goodput 是多少?对应什么比例?
  4. 用式 (2)、(3) 求:D = 0.4 秒、K = 1.6 时,到达率多大时流水线并行 2 段的平均 TTFT 开始低于张量并行 2 路?
  5. 分块预填充把一个 4096-token 的提示切成 512 的块。一共要重复读多少个 token 的 KV?换成 1024 的块呢?
  6. OPT-66B 一个 1000-token 请求的 KV 有多大?在 25 Gb/s 的链路上传要多久?这条链路每秒最多能支撑多少个这样的请求?
  7. 为什么 DistServe 的低带宽放置算法要求”同一段流水线的预填充与解码在同一个节点”?如果模型不用流水线并行(inter-op = 1),这个约束意味着什么?
  8. DistServe 用”拉”的方式传 KV。如果改成预填充实例算完就”推”给解码实例,突发流量时会发生什么?
  9. KV 感知路由的代价 = 排队时间 + w × 预填充时间。w = 0、w = 1、w → ∞ 各对应什么策略?为什么 w = 1 有特别的含义?
  10. 解码节点在生成第 500 个 token 时故障。对比”客户端重试”和”迁移”两种恢复方式各需要重新计算多少 token;为什么迁移的那次预填充比 500 个解码步快得多?

参考答案

  1. 预填充 L 个 token 时每个权重复用 L 次,算术强度 ≈ L FLOPs/字节(2 FLOPs × L / 2 字节),L > 153 就超过 A100 的屋脊点。解码批 B 时线性层的强度 ≈ B,但还要读批里所有请求的 KV(每个 token 800 KiB × 上下文长度),这部分只有很少的计算,把整体强度压在 50 左右(01 号脚本),远低于 153。
  2. 0.2 + 0.04 × 299 = 12.16 秒。卡顿后平均 TPOT = 0.95 × 0.04 + 0.05 × 0.3 = 0.053 秒 > 50 ms,不达标——少数长卡顿就能拉高平均值(P99 的 TBT 更明显)。
  3. n 张预填充卡、k 张解码卡:min(6n, 15k)/(n + k)。5P2D:min(30, 30)/7 = 4.29;2P1D:min(12, 15)/3 = 4.0;3P1D:min(18, 15)/4 = 3.75。最佳 5P2D,每张 GPU 约 4.29(理想的连续值是 1/(1/6 + 1/15) = 4.29)。
  4. 令 D + RD²/(4(2 − RD)) = D/K + RD²/(2K(K − RD)),D = 0.4、K = 1.6。逐点算:R = 1:流水线 0.425、张量 0.292;R = 2:0.467、0.375;R = 2.7:0.517、0.510;R = 3:0.550、0.625。交叉点约 R ≈ 2.74 请求 / 秒(张量并行的稳定上限是 K/D = 4,流水线是 2/D = 5)。K 越小,交叉点越低——张量并行越早被超越。
  5. N = 8 块:512 × (0 + 1 + … + 7) = 512 × 28 = 14,336 个 token(提示长度的 3.5 倍)。1024 的块:N = 4,1024 × 6 = 6,144(1.5 倍)。
  6. 2.25 MiB × 1000 ≈ 2.36 GB;25 Gb/s = 3.125 GB/s,约 0.75 秒;每秒最多约 1.3 个。
  7. KV 只在对应的层之间传;同一段的层在同一个节点里,传输就只走 NVLink。inter-op = 1 时每个实例都在一个节点内,意味着一对预填充 + 解码实例必须挤进同一个节点(权重要放两份),大模型(如 175B)根本放不下。
  8. 突发时预填充实例会一下子把大量 KV 推给解码实例,解码实例的显存放不下就得拒绝、抢占或 OOM;“拉”的方式让预填充实例的显存充当缓冲区,解码实例按自己的容量取,两边各按自己的节奏工作。
  9. w = 0:只看排队,最空闲优先;w → ∞:只看命中;w = 1:代价恰好是”排队时间 + 预填充时间” = 预计的 TTFT,即贪心地最小化每个请求的 TTFT。
  10. 重试:重新预填充提示 + 重新解码 500 个 token(还要等它们一个个生成);迁移:一次长度为”提示 + 500”的预填充。预填充一次处理所有 token,是计算受限的矩阵乘,几百毫秒;500 个解码步每步都要读一遍权重,几秒到十几秒。

11. 延伸阅读 · Further reading

  • DistServe:Zhong et al. (2024),OSDI;代码 github.com/LLMServe/DistServe。
  • Splitwise:Patel et al. (2024),ISCA——按阶段选硬件。
  • Sarathi-Serve:Agrawal et al. (2024),OSDI——分块预填充与无卡顿调度。
  • TetriInfer:Hu et al. (2024);DéjàVu:Strati et al. (2024)——同期的分离 / KV 流式传输工作。
  • DeepSeek-V3 技术报告(2024)§3.4:预填充与解码分离、各自的并行与冗余专家。
  • NVIDIA Dynamo:github.com/ai-dynamo/dynamo(KV 路由、规划器、KVBM、NIXL、AIConfigurator、Grove)。
  • vLLM 的分离部署示例:docs.vllm.ai 的 disaggregated serving 一节(slides 推荐的学习用例子)。
  • Mooncake:Qin et al. (2025),FAST 最佳论文——以 KV 缓存为中心的分离架构(附加讲 A2)。

12. 下一讲预告 · Next lecture

分离部署把 KV 缓存从”GPU 里的临时状态”变成了”在机器之间搬来搬去的数据”。顺着这个方向再走一步:KV 缓存能不能像文件一样存下来、压缩、跨请求跨实例共享,甚至拼接(不是前缀的复用)?第 27 讲是 Junchen Jiang 的嘉宾讲座:CacheGen(把 KV 当视频来编码,压缩 3–10 倍)、CacheBlend(RAG 的多个文档各自缓存、拼起来只重算一小部分 token)和 LMCache(把 KV 缓存从推理引擎里分离出来的开源系统)。

← 返回课程目录