跳到主要内容
推理优化

7.1 混合 Batching 的问题:Prefill 对 Decode 的定量干扰

Prefill(Compute Bound)与 Decode(Memory Bound)的计算特性差异、混合 batching 的干扰机制、Decode 尾延迟被拖慢的定量分析、chunked prefill 的局限

PD解耦混合BatchingPrefillDecode尾延迟Chunked Prefill

第 2 章讲过 Prefill 和 Decode 是自回归的两个阶段,Continuous Batching(第 3 章)把它们混在一个 batch 里提高吞吐。但”混在一起”有代价:Prefill 和 Decode 的计算特性截然相反,同卡共处会互相拖累。这一节先定量分析”混合”的问题——它是第 7 章所有解耦方案的动机。理解干扰的机制和数字,才能判断什么时候该解耦、什么时候不用。

📑 目录


1. 两个阶段的本质差异:算力饥渴 vs 带宽饥渴

先复习第 1/2 章的核心结论,用硬件指标把它钉死:

维度Prefill(提示处理)Decode(逐 token 生成)
单步计算量处理整个 prompt(如 4K token)——矩阵很大只算 1 个新 token——矩阵很小
瓶颈Compute Bound(算力饥渴)Memory Bound(带宽饥渴)
硬件需求FLOPS 越高越好显存带宽越大越好
理想资源A100/H100 这类高算力卡高带宽卡(如 A100 的 2TB/s 带宽)
关键延迟指标TTFT(首 token 时间)TPOT / ITL(每 token 时间)

📌 关键点:一个直觉实验——同样的矩阵乘法,4K token 的 Prefill 一步的计算量等于 Decode 4096 步之和。所以 Prefill 想把 GPU 的算力吃满(大矩阵、高利用率),Decode 则每步只搬得动小矩阵(算力闲置、带宽打满)。这两种需求在同一张卡上是互相排斥的——这就是干扰的根源。

1.1 为什么 Decode 是带宽墙

Decode 每步只生成 1 个 token,但必须把全部模型权重(如 70B = 140GB)从 HBM 搬一遍才能算一次前向。搬权重的时间决定了步长:

单步时间权重大小显存带宽=140 GB2 TB/s=70 ms\text{单步时间} \geq \frac{\text{权重大小}}{\text{显存带宽}} = \frac{140\text{ GB}}{2\text{ TB/s}} = 70\text{ ms}

算力在这 70ms 里绝大部分闲置——Decode 的本质是”把权重搬到算力面前”的搬运工。任何让 Decode 的”搬运时间”变长的东西(比如 Prefill 抢占了带宽)都会直接反映到 TPOT 上。


2. 混合 Batching 的干扰机制

Continuous Batching(第 3 章)让 Prefill 和 Decode 的步骤交替出现在同一个 batch 里。干扰发生在两个层面:

2.1 带宽争夺

一个 batch 里既有 Prefill 的大矩阵(需要大量带宽搬权重+激活)又有 Decode 的小矩阵时,两者竞争同一个 HBM 带宽。Decode 步骤的实际可用带宽下降,TPOT 直接变长。

2.2 计算资源抢占(更隐蔽)

GPU 上 Prefill 的 GEMM 与 Decode 的 GEMM 会在 SM(流处理器)上竞争。现代推理引擎(如 vLLM)虽然做 CUDA Graph 和 kernel 调度,但大 prefill kernel 与小 decode kernel 的并发执行仍然会互相干扰——尤其当 Prefill 的 kernel 占满 SM 时,Decode 的 kernel 只能排队等。

💡 提示:直觉类比——高速公路(SM/带宽)上,一辆重型卡车(Prefill)和一批小轿车(Decode)并排跑,卡车慢且占道,小车被堵在后面。混行让两类车都变慢,但小车(Decode)的尾车(P99)最惨

2.3 头部阻塞(Head-of-Line Blocking)

长 prompt 的 Prefill 一旦开始,会长时间占用 GPU——期间新到的 Decode 请求只能排队。这造成两类连锁反应:

  1. 排队延迟:Decode 请求的 TTFT 被无关的长 Prefill 拖长
  2. 突发放大:Prefill 突发(burst)越猛,Decode 的尾部延迟抖动越大

3. 定量账:Decode 尾延迟被拖慢多少

3.1 典型数字

DistServe(OSDI’24)的系统化测量给出了量级:混合 batching 下,Decode 的 P95 TPOT 可以被拖慢 3-5 倍(对比纯 Decode 场景),TTFT 的 P90 也随请求速率上升急剧恶化。直观理解这个数字:

  • 纯 Decode 场景:TPOT P95 ≈ 25-40ms(13B 模型量级)
  • 混入 Prefill 后:TPOT P95 飙到 100ms+,甚至 200ms

3.2 为什么是”尾”延迟

Decode 的平均延迟受影响小(大多数步骤没撞上 Prefill),但只要撞上一次长 Prefill,该请求的那一步就被拉长一个数量级。P95/P99 对”撞上”敏感,所以:

干扰对尾延迟的放大干扰对平均延迟的放大\text{干扰对尾延迟的放大} \gg \text{干扰对平均延迟的放大}

📌 关键点SLO(服务等级目标)通常盯分位点(P95/P99),不盯均值(7.4 细讲)。均值好看、尾部爆炸的服务,在 SLO 评估下依然是”不达标”。这就是混合 batching 最致命的地方——它让尾部不可控。

3.3 请求长度的放大效应

干扰程度与 prefill/decode 的比例强相关:

工作负载特征干扰严重度原因
短 prompt + 长输出(聊天)Prefill 小,但 decode 长、尾部持续暴露
长 prompt + 短输出(文档总结)Prefill 大矩阵,抢带宽时间长
混合负载(长短不均)最高不可预测的突发交织

4. 干扰的另一面:资源耦合

DistServe 指出的第二个问题——资源耦合(Resource Coupling)——比干扰更隐蔽:

  • Prefill 的理想配置:TP 大(算力优先)、batch 大(吞吐优先)
  • Decode 的理想配置:TP 适中、并发大(带宽优先)

混合部署时,两个阶段被迫共享同一个并行度、同一个 GPU 池、同一个调度器。于是:

  1. 为 Prefill 加的卡/并行度,Decode 用不上(甚至被拖慢)
  2. 调 TTFT 的参数(TP、chunk size)会影响 ITL,反之亦然——两个目标互相锁死
  3. 资源按”峰值需求”配置(为了满足 P99 TTFT 多配的卡,在 decode 长尾时闲置)

📌 关键点:耦合的本质是”一个旋钮调两个目标”。解耦的核心收益之一就是打破这种耦合——prefill 池和 decode 池各自调参(vLLM 官方文档把”TTFT/ITL 独立调优”列为 disaggregated prefill 的首要动机)。


5. Chunked Prefill:缓解但没根治

“既然大 Prefill 抢带宽,把它切小不就行了?“——vLLM 的 Chunked Prefill(第 2 章讲过)确实把大 prefill 切成多个 chunk,与 decode 交错执行,缓解了带宽抢占。但它有根本局限:

  1. 切多碎才合适? chunk size 取决于负载特征(prompt 长度分布、并发、显存),实践中极难找到正确的值(vLLM 官方文档原话:it’s hard to figure out the correct chunk size value)
  2. 重复读 KV:每个 chunk 都要把之前 chunk 的 KV cache 从 HBM 重新加载一遍——切 N 块就多读 N-1 遍,Prefill 自身的带宽开销上升
  3. piggyback 收益递减:chunk 切到接近 GPU 饱和时,留给 decode token 的”搭车”位置就少了

💡 提示:Chunked Prefill 的本质是”把大干扰切成小干扰”——它不消除干扰,只让干扰更均匀、更可控。解耦则是”让干扰不存在”:两个阶段根本不在一张卡上。这也是官方文档说”disaggregated prefilling is a much more reliable way to control tail ITL”的原因。


6. 什么时候问题严重

判断你的负载是否需要解耦(下一节讲方案),先对照这个清单:

信号说明
P99 TPOT 达标但 P95/P99 抖动大典型的 prefill 干扰特征(如果均值也差,可能是别的问题)
长 prompt 占比高(>2K token)Prefill 大矩阵,干扰时间长
并发高 + 请求长度不均突发交织频繁,尾部不可控
TTFT 和 TPOT 都要严格 SLO一个旋钮调两个目标,必然顾此失彼
生产有明确的 SLO 分位点要求均值吞吐再高,SLO 不达标等于白跑(7.4 的 goodput)

对照完如果中了 2-3 条,就值得认真考虑解耦(7.2 起)。如果负载简单(短 prompt、低并发、无严格 SLO),混合 batching + chunked prefill 通常够用——解耦是有成本的,别为不存在的病开刀。

📌 关键点:本节最重要的判断标准——看尾部,不看均值。先拉一段生产请求的 TTFT/TPOT 分位点曲线,如果 P95 出现”脉冲式”的尖峰,那就是 prefill 干扰;如果尖峰与长 prompt 的到达时间相关,基本实锤。7.6 实战会教你量化这个过程。


📝 总结

  • 本质差异:Prefill Compute Bound(算力饥渴)、Decode Memory Bound(带宽饥渴)——同卡共处必然互抢
  • 干扰机制:带宽争夺 + SM 抢占 + 头部阻塞,Decode 尾延迟(P95 TPOT)可被拖慢 3-5 倍
  • 资源耦合:TTFT 与 ITL 共用一个旋钮,调参互相锁死,资源按峰值配置
  • Chunked Prefill 只缓解不根治:chunk size 难调、重复读 KV、piggyback 递减
  • 判断信号:尾部抖动、长 prompt、严格双 SLO——中了再解耦,别过度设计

🎯 自我检验清单

  • 用”算力饥渴/带宽饥渴”解释 Prefill 与 Decode 的差异?各自的关键指标是什么?
  • 为什么 Decode 单步时间 ≥ 权重/带宽?70B 模型在 2TB/s 卡上单步下限是多少?
  • 干扰的三个机制分别是什么?为什么 Decode 尾延迟受害最深?
  • “资源耦合”是什么意思?为什么说一个旋钮调两个目标?
  • Chunked Prefill 为什么治标不治本?三个局限分别是什么?
  • 你的生产负载要不要解耦?用哪几条信号判断?

📚 参考资料