论文:USENIX 官方页面 · 论文 PDF · 代码:Sys-KU/FastPP。
1. 背景:问题不是并行度,而是在线负载的不均衡
大模型参数和 KV cache 经常超过单卡显存。KV cache(键值缓存)保存已处理 token 的注意力键和值,使后续生成可以复用历史计算;prefill(预填充)处理输入提示并建立缓存,decode(解码)则利用缓存逐步生成输出 token。张量并行(tensor parallelism,TP)沿层内维度切分计算,让多张卡共同完成同一层;它能缩短单次计算,但每层都需要多 GPU 集体通信。互连带宽不足时,这些同步成为服务瓶颈。流水线并行(pipeline parallelism,PP)则沿模型深度切分层,将相邻阶段之间的中间激活传给下一张卡,通信模式与体量不同。
PP 并非免费收益。请求必须依次经过各阶段,而阶段之间只有同时存在多个微批(microbatch)时才能有效重叠。在线推理又不同于长度固定、批次规律的训练:请求随机到达,prompt 长度和输出长度不同,prefill 与 decode 会混合。一个阶段处理长 prefill 时,其他阶段可能先完成并等待,空闲时间就是流水线气泡。
衡量服务质量需要先区分两个延迟:TTFT(time to first token)是请求到首 token 的等待时间,TPOT(time per output token)衡量后续 token 的平均生成间隔。SLO 是服务延迟目标;P90 表示按对应指标排序后的第 90 百分位。本文的 goodput 指 P90 TTFT 和 P90 TPOT 均满足目标时的最高请求到达率。两个 P90 分别达标,不意味着至少 90% 的请求同时满足两项 SLO:两项超标的请求可能不同。后文 Figure 14 使用的是另一种口径——逐请求同时达标的比例。
论文 Figure 1 展示了未充分优化 PP 的反例:Qwen2.5-32B、Azure Conversation 和四张 PCIe A100 上,在较高请求率下 PP 的 P90 TTFT 低于 TP,但 PP 因流水线气泡导致 TPOT 更早触及约束;该图里 TP 可持续的请求率是 PP 的 1.2 倍。论文并没有证明“PP 总比 TP 快”,而是追问怎样降低 PP 独有的不平衡。
与 Figure 9 的关系:Figure 1 使用该图的 PP 基线;Figure 9 则针对每种负载离线选择最佳静态 PP 块。两图不能当成同一配置比较,TP 的阈值数值也不完全相同,不能仅凭图表认定其余实验条件一致。
预备知识:分块与三种气泡
Chunked prefill 将长 prompt 拆成若干 token 块,与 decode 请求混合执行。这里的块大小用于限制一次微批处理的 token 工作量:一个 prefill 请求可以贡献多个输入 token,而一个活跃 decode 请求在一次生成迭代中通常贡献一个 token。混合批次中,两者共同影响执行工作量;具体预算与调度细节取决于实现。小块减少对其他微批的阻塞,但过小会降低批处理效率并抬高排队时间。
论文 Figure 2 将失衡分成三类:P-P 是两个 prefill 微批长度不同;P-D 是 prefill 与 decode 的计算量不同;D-D 是两个 decode 微批所含请求数量不同。前两类可通过限制 prefill 工作量缓解;第三类即使没有 prefill 也会持续出现,因此需要另外的重平衡机制。
示例 1:分块如何缩短其他微批的等待
以下是自绘的两阶段调度示意,假设 A 的每个阶段各需 4 个时间单位,B 每个阶段各需 1 个单位。两图从 A 在第一个阶段开始,灰色格包含启动和排空等待;橙色格专门标出 B 已在 GPU 0 完成、却要等待 GPU 1 处理完 A 的时段。数字不是论文实测,也不是对所有硬件的性能保证。
不分块:A 先后占用两个阶段各 4 格。B 在第 5 格完成 GPU 0 的处理,等到第 9 格才能进入 GPU 1。
分块后:假设 A 分成每阶段各需 2 格的 A1、A2,调度器允许 B 在两块之间进入。B 在第 3 格完成 GPU 0 的处理,第 5 格进入 GPU 1;A2 则继续在两个阶段执行。
示意中 B 的阶段间等待从 3 格减少为 1 格;启动、排空空闲仍存在。分块收益取决于实际计算时间和调度方式,块太小也可能降低批处理吞吐。论文 Figure 5 展示了其流水线分块示意。
运行时控制流程
反馈方向:执行结果 → 状态测量 → 下一轮调度。动态分块主要应对 P-P / P-D,decode 重平衡主要应对 D-D;它们是调度阶段中针对不同失衡的机制。
2. 方法:让分块大小随系统状态变化
2.1 优化目标与控制信号
两种分块策略遵循同一原则:在系统能处理当前请求负载、并尽量满足 TPOT 约束的前提下,优先使用较小块以减轻气泡。若块太小,prefill 吞吐跟不上到达流量,队列累积,TTFT 变差;若块太大,较慢的 prefill 迭代可能阻塞其他微批,TPOT 变差。
理解反馈控制可把 slack 写成下式,其中 $S$ 是对应 SLO,$L$ 是观测延迟;正值表示还有余量,负值表示已经超标。这个式子用于解释文中的 slack,不能理解为运行时必然逐请求精确测量。
首 token 余量变小意味着队列压力上升;输出 token 余量变小意味着当前 decode 受阻的风险上升。
2.2 贪心策略:用反馈逐步调整
论文 Algorithm 1 将候选块限制在离散集合 $\mathcal C$,例如以 128 token 为步长。初始值取最小块,更新间隔为流水线深度 $D_p$ 个调度迭代:一个微批走完整条流水线之前,块大小变化的效果尚不能完整显现。
第一优先级是内存。若空闲 KV cache 比例低于水位,算法把块重置到大于当前运行请求数的最小候选值,优先推进在途请求并回收缓存。这是降低内存压力的启发式,不构成任意条件下避免 OOM 的形式化保证。
内存充足时,若 TPOT 已超标或 TTFT 余量很大,就减小块;若 TTFT 余量紧张而 TPOT 仍有充足余量,则增大块。将论文中的条件概括如下;$\delta$ 是步长,$\alpha,\beta,\gamma$ 是阈值,集合边界处需要截断:
decode 有危险或请求较少时缩小块;只有队列有压力且 decode 留有余量时才扩大块。KV 低水位检查优先于此式。
论文作者明确指出贪心法的局限:它只看过去的指标,且每次只改变一个步长;流水线反馈有延迟,其他阶段的大块还会污染延迟信号。流量突变时,控制器可能一直在追赶变化中的合适值。实现中的具体阈值和保护逻辑比论文伪代码更细,不应混为完全相同。
2.3 预测策略:先估算,再选择最小可行块
预测式动态分块(DCPpred)将等待队列、运行中批次、KV 空间和近期到达率作为系统状态,对每个候选块预测迭代延迟与吞吐量。它把服务要求转化为两个方向相反的约束:TPOT 提供块大小的上限,处理到达请求与积压所需的 prefill 吞吐提供下限。
延迟预测器 ALP 将一次迭代的时间拆为离线和在线两部分:
大头线性层成本主要由本次 token 数 $N_{\mathrm{tokens}}$ 决定,可先在目标硬件上离线测量;$\alpha_0,\alpha_1$ 是拟合系数。原文在 128–2048 token 范围做离线测量,实际硬件上有离散台阶,不应把这个线性近似视作普适物理定律。
注意力开销随上下文和请求构成变化,因此论文用三个特征估计在线分量:
第一项是新 prefill 块与已有上下文之间的注意力,第二项是当前块内部注意力,第三项是 decode 访问历史上下文;求和覆盖相应批内请求。$L_{\mathrm{past}}$ 是历史前缀长度,$L_{\mathrm{pre}}$ 是当前块长度,$L_{\mathrm{dec}}$ 是解码请求上下文长度,$\epsilon$ 表示残差或噪声。
每次迭代把实测延迟与离线预测的差额作为反馈,使用递归最小二乘(RLS)在线调整注意力系数。RLS 的协方差矩阵有助于处理平方项与线性项量级差异;遗忘因子提高近期观测的权重。预测器并非消除误差,而是在轻量和可适应性之间取舍。
Figure 6 给出选择流程。图中预测吞吐下界排除了 128 和 256;预测延迟上界排除了 640 等较大的候选,384 和 512 均位于可行范围,故选择更小的 384。图中的界限和数字是论文的流程示例。对块 $c$,用 $D_p\hat T_{\mathrm{iter}}(c)$ 近似该微批完成一轮流水线的延迟;其中 $D_p$ 为阶段数,$\hat T_{\mathrm{iter}}$ 为预测的单阶段迭代时间。该乘法是调度近似,不是整个请求从到达到最后一个 token 的端到端完成时间;真实延迟也受其他微批及阶段波动影响。记 $\hat R(c)$ 为预测 prefill 吞吐,$R_{\min}$ 为处理到达流量及老化积压所需的吞吐,可将选择原则概括为:
先排除预计伤害 TPOT 的大块,再从能跟上需求的候选中选最小块。这是按论文文字归纳的优化表达式,并非作者声称的全局最优证明。
吞吐下界由两部分相加:滑动窗口估计的新请求输入 token 到达速率,用于防止新流量持续堆积;超过等待阈值的请求则按其 prompt token 总数除以剩余 TTFT 预算,估算额外的积压追赶速率。两部分相加,是因为系统既要跟上新请求,也要尽快处理已等待过久的请求;这只是调度估算,并非逐请求按时完成的保证。
例如,新流量约为 5,000 token/s,超过等待阈值的请求共有 5,000 个 prompt token,TTFT 剩余预算按平均等待时间估算为 2 秒,则积压追赶需求为 2,500 token/s,合计下界为 7,500 token/s。数字仅用于说明论文方法。若没有候选同时满足吞吐与 TPOT 条件,论文选择仍满足 TPOT 的最大候选以尽力排空队列;若连最小块也不能满足 TPOT,所引用源码返回最小候选作为退化处理,不能保证 SLO。
2.4 Delay scheduling:主动暂缓一部分 decode
动态 prefill 块不能直接解决纯 decode 迭代中的 D-D 失衡。论文 §4.2 依据硬件执行时间对 token 数的台阶状变化调整微批:例如 Figure 3c 所示,129 token 的线性层成本与 256 token 接近,略微超过边界却会让该微批明显拖慢其他阶段。
当批量只比硬件效率边界大一点时,系统可暂缓超出的请求,让批次回落到边界;若超出更多,则朝各微批平均请求数重平衡,必要时恢复先前暂缓的请求。Figure 7 的示例显示,暂缓 E、F 后,其他微批可以更均匀地前进,等空位出现再恢复。这里的“迁移”主要是调度批次的请求重组,不应无条件理解成把整份 KV cache 从一张 GPU 复制到另一张 GPU。
请求选择体现延迟指标的权衡:TPOT 余量不足时,论文优先暂缓较老请求,以保护较新请求;作者认为较老请求更能承受额外延迟。直观地说,如果按请求已生成 token 的平均间隔衡量 TPOT,一次额外等待会分摊到已有输出历史,但具体影响仍取决于请求与统计口径,并不保证老请求不会超标。TPOT 余量充足时则优先暂缓较新请求,让较老请求更快结束、释放 KV cache。暂缓仍会拉长被选请求的下一次 token 间隔。
例如,若一个微批有 130 个 decode 请求,硬件高效边界为 128,且超出的 2 个请求位于允许暂缓的阈值内,调度器可以先处理 128 个,待其他微批出现空位后再恢复这 2 个。边界和阈值取决于硬件与配置;总体等待减少并不意味着每个请求都受益。
3. 论文与开源实现如何对应
作者仓库是 SGLang 0.4.1 的 fork;README 标明动态分块与批次重平衡默认关闭,分别由 --enable-dynamic-chunk 和 --enable-batch-rebalancing 开启。以下代码为固定提交的短摘录,仅用于说明机制;论文实验基线和仓库当前默认值应分别核对。
贪心控制器
python/sglang/srt/managers/dynamic_chunk_controller.py:224 对应 Algorithm 1 的 KV 压力优先、TPOT/TTFT 双信号调整:
if kv_pressure_active:
next_chunk = ((min(running_req_num) + 64) // 128 + 1) * 128
elif restore_chunk is not None:
next_chunk = restore_chunk
elif sched.tpot > SLO_TPOT * self.tpot_violation_ratio or sched.ttft < SLO_TTFT * self.ttft_low_ratio:
next_chunk = max(cur_chunk - base_chunk, min_chunk)
elif sched.ttft > SLO_TTFT * self.ttft_high_ratio and sched.tpot < SLO_TPOT * self.tpot_safe_ratio:
next_chunk = min(cur_chunk + base_chunk, max_chunk)代码使用直接观测的延迟阈值,并增加恢复块大小的分支;不能把具体常数直接当成论文 Algorithm 1 的数学阈值。预测式入口为同文件 decide_chunk_alp:262,候选选择位于 _select_alp_chunk_with_lazy_prediction:441。
批次重平衡
python/sglang/srt/managers/batch_rebalancer.py:80 根据 TPOT 压力决定优先级,也允许通过参数强制模式:
if self.br_mode == "tpot_first":
use_tpot_first = True
elif self.br_mode == "e2e_first":
use_tpot_first = False
else:
use_tpot_first = tpot_signal >= TPOT_FIRST_THRESHOLD
rebalance_mode = "TPOT_FIRST" if use_tpot_first else "E2E_FIRST"同一文件的 get_split_indices 与后续 split_batch/merge_batch 负责在 running 和 pending 批次间调整请求;scheduler.py:889 调用重平衡。源码的模式与论文策略方向对应,但仅凭这些片段不能证明论文每个实验配置与当前默认参数完全一致。
4. 实验:看清基线、负载与指标
环境为四张 NVIDIA A100 40GB,GPU 经 PCIe 4.0 连接主机;CPU 为 128 核 AMD EPYC 9754、内存 768 GB。模型为 BF16 Qwen2.5-32B 与 14B;框架为 SGLang 0.4.1、PyTorch 2.5.1、CUDA 12.4。到达率扫描使用泊松到达;另有 Azure 真实时间轨迹回放。原文 Figure 8 的 Azure、ShareGPT、CNN 平均输入/输出 token 长度分别为 1161/212、226/199、883/65;CNN-Reversed 交换输入与输出分布以构造 decode-heavy 条件。
主要 SLO 为 P90 TTFT 不超过 2000 ms 且 P90 TPOT 不超过 200 ms。TP 使用 2048 token 默认块;PP 同时比较多个静态块,其中 PPstatic 指按对应负载离线选出 goodput 最高的静态块。这个基线经过调优,因而与默认 2048 块不同。动态策略的主要收益既可能是 goodput,也可能是在 goodput 已接近时改善延迟。
4.1 32B:goodput 对比
| 工作负载(Figure 9) | TP | 最佳静态 PP | 预测 DCP | 预测 DCP + DS |
|---|---|---|---|---|
| AzureConv | 3.48 | 8.28(512) | 8.47 | 8.47 |
| CNN | 4.30 | 9.26(512) | 10.17 | 10.16 |
| ShareGPT | 12.45 | 32.46(512) | 36.09 | 36.16 |
| CNN-Reversed | 5.98 | 7.27(256) | 7.40 | 10.42 |
单位:请求/秒;数值直接摘自 Figure 9 柱状图,括号为最佳静态块 token 数。静态 PP 块的选择是各自负载上的离线最优,不是事先固定的统一配置。
Azure 上的主要提升已由调优静态 PP 获得:8.28 相对 TP 的 3.48 约为 2.38 倍;预测 DCP 的 8.47 只比该强基线高约 2.3%。因此不能把 8.47/3.48 全部归功于动态预测器。作者报告,在这个工作负载中,预测策略相对 PPstatic 的 TPOT 与端到端延迟最多分别降低 35% 和 31%;贪心策略对应 19% 和 18%。这些是文中报告的最大降幅,并非表中某个单独柱子的结果。
CNN-Reversed 的不同点是 DS:10.42 相对预测 DCP 的 7.40 约提高 41%,说明纯 decode 的微批不均衡不能靠调整 prefill 块充分处理。相反,Azure 等 prefill-heavy 场景中 DS 很少触发,因此增加它几乎不改变柱高。Figure 10 也表明,换成 14B 后 Azure 最佳静态块变成 1024,说明块大小依赖模型与工作负载。
4.2 尾延迟与预测模型消融
| 指标与条件 | 静态 PP | 贪心 DCP | 预测 DCP | 解释 |
|---|---|---|---|---|
| Azure,4 req/s,迭代 P90(Figure 11) | 51.68 ms | 29.56 ms | 21.53 ms | 预测式将迭代时间分布进一步压低 |
| Azure,4 req/s,迭代 P99(Figure 11) | 65.34 ms | — | 30.94 ms | 静态/预测约 2.11 倍,非端到端加速比 |
| CNN-Reversed,8 req/s,迭代 P90(Figure 11) | 28.94 ms | — | — | 预测 DCP + DS 为 24.53 ms |
Figure 11 支持机制解释:Azure 中 P90 迭代时间从 51.68 降至 21.53 ms,约降低 58%;这种局部迭代改善能缓解气泡,但不能直接当作整请求端到端延迟降幅。CNN-Reversed 里没有大量 prefill,DCP 自身收益有限,而 DS 能压低迭代 P90。
| 预测器(Table 1) | MAPE | 预测时间 ms | 模型大小 KB |
|---|---|---|---|
| 仅离线基线 | 15.85% | 0.000136 | 0.363 |
| 加入 prefix / prefill / decode attention | 3.48% | 0.002101 | 0.552 |
| 完整 ALP,含残差 | 3.26% | 0.002875 | 0.643 |
| 线性回归 | 4.26% | 0.000594 | 0.187 |
| 决策树集成 / 两层 DNN | 2.74% / 2.56% | 0.038217 / 0.046407 | 1330 / 570 |
引入注意力特征使 MAPE 从 15.85% 降至 3.48%,说明仅靠总 token 数不足以解释不同上下文。DNN 更准确,但作者未观察到有意义的端到端改善。预测误差可能让候选块被错误地判为可行或不可行;只有误差变化进一步影响调度选择或执行效果,才可能改变最终服务指标。因此预测精度更高不必然带来更好的服务质量。论文将 ALP 的离线线性层 profiling 与在线适配结合,不能说整个方法完全无需离线测量。
4.3 真实轨迹、严格 SLO 与公平性
Figure 14 将 AzureConv 前 15 分钟按 0.9 倍原始到达率回放,选择该缩放使调优静态 PP 的达标率约为 90%。TP、默认 PP2048、调优 PPstatic 的双 SLO 达标率分别为 1.9%、1.6%、92.5%;贪心、预测、预测加 DS 分别为 93.5%、94.5%、94.6%。这是逐请求双 SLO 达标比例,与 Figure 9 使用的 P90 约束下最高请求率不是同一指标,也不是同一实验设置。
Figure 12 显示更严约束可能使方案失效:32B、SLO 缩放 0.2 时,最小候选块都不能满足 TPOT,所有 PP 类方案 goodput 为零。Figure 13 的合成 decode-heavy 场景中,DS 相对预测 DCP 平均与 P99 E2E 分别减少 4062 ms 和 8088 ms,但被暂缓请求使 P99 TPOT 恶化 15%。因此,调度器优化总体指标时应同时监测被牺牲请求的尾部体验。
5. 局限与适用边界
作者指出的限制:前述贪心反馈滞后、严格 SLO 下无可行块,以及 DS 对尾部 TPOT 的影响,都会限制收益;DS 在严格 SLO 下还可能因未积累足够请求而达不到激活阈值。
独立判断:实验集中在单节点四张 PCIe A100 和两个同系列稠密 Qwen 模型,尚不能外推到 NVLink、高速跨节点网络、不同 GPU/NPU、MoE 或异构阶段。TP 的通信成本与 PP 气泡都随拓扑、并行度和内核变化;尤其 Figure 1 的普通 PP 已展示反例。真实轨迹仅报告一个缩放比例和窗口,真实突发、超长上下文、取消请求、混部干扰与多租户公平性仍需更广泛验证。
此外,预测器对滑动窗口到达率和历史特征变化的适应能力可能受突发分布漂移影响;论文提供的 MAPE 是指定 Azure 工作负载上的结果,不能替代在新环境下的重新 profiling 与端到端测试。固定 SLO 下的 P90 目标也可能掩盖少数请求更严重的饥饿,应同时检查 P99、最大等待时间、逐请求达标比例及 KV 占用。
部署时可先在目标拓扑上测 TP 与多种静态 PP 块,确认瓶颈来自通信还是气泡;再分别开启动态块与重平衡,按 prefill-heavy、decode-heavy 和真实到达轨迹测量。最好报告每种方案的吞吐、TTFT/TPOT 分位数、端到端延迟、KV 使用率及尾部公平性,同时固定模型、精度、缓存和基线参数。
6. 结论
论文的贡献是把在线 PP 气泡拆解为可观察的工作量失衡,并分别用基于 SLO 的动态 prefill 分块与 decode 微批重平衡处理。实验中,针对 PCIe 环境经过调优的 PP 已显著优于默认 TP;动态策略进一步改善延迟,DS 则在 decode-heavy 条件下提供明显额外收益。方法的可迁移价值在于控制思路,具体收益仍取决于拓扑、模型、负载与 SLO。
参考文献
- Soonjae Hwang and Jeongseob Ahn. Revisiting Pipeline Parallelism for LLM Serving. OSDI, 2026.
- Amey Agrawal et al. Taming Throughput-Latency Tradeoff in LLM Inference with Sarathi-Serve. OSDI, 2024.
- Lianmin Zheng et al. SGLang: Efficient Execution of Structured Language Model Programs. NeurIPS, 2024.