07. Serving Scheduling and PD Disaggregation | Serving 调度与 PD 分离
页面目标
从多个请求同时到达开始,观察 Prefill 和 Decode 如何争用计算、显存与队列资源,再理解 Continuous Batching、PD 分离和服务级调度的作用。
调度问题的四个层次
本节把“调度”按决策范围逐层展开。前一层决定当前一步做什么,后一层决定更多请求如何共享资源;因此 36、37、38 不是三个并列的 backend 名词,而是从执行单元走向服务拓扑的学习顺序。
| 层次 | 调度者在决定什么 | 主要输入 | 主要结果 | 对应入口 |
|---|---|---|---|---|
| 单步 Decode 调度 | 当前 Decode step 给哪些活跃请求分配 token 计算 | 请求状态、优先级、剩余长度 | 本轮执行顺序与步数 | 36 |
| Cache 资源调度 | 请求能否继续占用 Cache,何时暂停、驱逐或恢复 | Cache 容量、Block、等待时间 | 可接纳请求数与公平性 | 37 |
| 批次与队列调度 | 哪些 Prefill / Decode 请求组成下一批 | 到达时间、Prompt 长度、Decode 工作量 | 批次效率、排队和尾延迟 | 38 的前置机制、70 的实验 |
| 服务池调度 | 请求进入哪个实例、Prefill 池或 Decode 池 | GPU 资源、链路、服务等级 | 服务吞吐、P99 和资源隔离 | 38、70、79–81 |
这里要区分三个容易混淆的对象:
- 请求调度决定“先服务谁、这一轮服务谁”;
- Cache 管理决定“请求的状态放在哪里、能保留多久”;
- PD 分离决定“Prefill 和 Decode 由哪个资源池执行”。
三者可以协同,但改动一个对象并不等于同时完成另外两个对象的优化。例如扩大 Cache 容量可能提高可接纳并发,却不会自动改善队列公平性;把 Prefill 和 Decode 拆成两个池,也需要重新检查跨池通信和负载平衡。
当请求量超过当前资源能够稳定处理的范围时,调度器还要做“是否接纳”的决定。接纳控制不是简单拒绝请求,而是根据 Cache 预算、队列等待、服务等级和预计工作量选择排队、限流、降级或转移。它决定系统是在负载上升时保持 P99,还是让所有请求一起变慢。
| 接纳动作 | 触发条件 | 保护对象 | 需要观察 |
|---|---|---|---|
| 排队 | 当前资源短时不足,但预计可以恢复 | 请求完整性 | queue time、P99、队列长度 |
| 限流或拒绝 | 队列或 Cache 超过安全水位 | 已接纳请求的 SLA | rejection rate、超时率、P99 |
| 降级 | 质量目标允许降低资源开销 | 整体可用性 | 输出长度、dtype、质量指标 |
| 转移或扩容 | 单实例或单池持续饱和 | 服务容量 | 利用率、迁移/通信时间、吞吐 |
核心机制
Serving 调度面对的不是单个算子,而是请求之间的资源竞争。先用“单 backend、基础批处理、单实例、不开启 PD 分离”的 Serving 配置建立参考行为,固定请求分布、并发度和输出长度,记录 TTFT、TPOT、吞吐、P99 与峰值显存。Prefill 通常带来突发计算和显存申请,Decode 则需要持续、稳定地读取 KV Cache;如果把两者简单混在同一批次,长 Prompt 可能阻塞正在生成的请求。因此需要分别观察批处理、队列、Cache 预算和 GPU 资源分配。
vLLM 和 SGLang 都是 Serving backend,但它们适合观察的机制重点不同:vLLM 适合作为统一基线,关注 PagedAttention、连续批处理和调度;SGLang 更适合观察 RadixAttention、前缀复用、结构化程序和 PD 分离。下面的图片先说明共同的请求链路,再对照两种 backend 的侧重点。
| Backend | 重点机制 | 更适合观察的问题 | 对应项目 |
|---|---|---|---|
| 单 backend 基线 | 基础批处理、单实例、不开启 PD 分离 | 建立 TTFT、TPOT、吞吐、P99 和峰值显存参照 | 66 的基础 Serving 配置 |
| vLLM | PagedAttention、连续批处理、请求调度 | Cache 分配、吞吐、TTFT / TPOT、P99 | 66 基线与 backend 对照、70 调度 |
| SGLang | RadixAttention、前缀复用、结构化执行、PD 分离 | Prefix Cache、共享前缀、请求组织与资源拆分 | 66 可选对照、69 缓存、70 调度 |
| 机制 | 主要解决的问题 | 观察指标 |
|---|---|---|
| Continuous Batching | 请求到达时间不同、生成长度不同 | 吞吐、TPOT、P99 |
| Chunked Prefill | 单次长 Prefill 阻塞其他请求 | TTFT、P99、Decode 抖动 |
| Prefill / Decode 分离 | 两类计算互相争用资源 | TTFT、TPOT、GPU 利用率 |
| 队列与资源调度 | 并发、容量和服务等级变化 | 排队时间、并发容量、SLA |
把 Serving 调度看成一个闭环:请求进入队列后,系统根据可用 Cache、Prefill/Decode 计算预算和服务等级选择下一批请求;运行结果再反馈给下一轮调度。这样可以把“调度策略更好”拆成可观察的资源账本和服务结果,而不是只看 GPU 利用率。
| 调度决策依据 | 影响的系统对象 | 需要观察的结果 |
|---|---|---|
| 等待时间与服务等级 | 队列顺序、请求公平性 | P50/P99、最大等待时间、超时率 |
| Prompt / Decode 工作量 | Prefill 与 Decode 的批次组成 | TTFT、TPOT、批次利用率 |
| Cache 可用容量 | 是否接纳、暂停或驱逐请求 | Cache 使用量、OOM、并发容量 |
| 实例与链路状态 | 单实例、PD 池和跨设备通信 | 吞吐、通信时间、资源利用率 |
学习和实验时按同一顺序推进:先用 36 验证单步请求选择,再用 37 加入 Cache 容量和暂停/恢复,再用 38 观察批次组织与 Prefill / Decode 资源隔离,最后在 70 中固定 workload,比较调度策略对 TTFT、TPOT、throughput、P99、并发容量和公平性的影响。这样得到的结论才能说明“哪一层调度改善了什么”,而不是只报告 GPU 利用率变化。
多 GPU 和自动扩缩容属于本节的扩展出口。它们不改变前面的四层调度定义,而是把服务池、通信和容量决策放大到多实例环境:先确认单实例调度口径,再测跨 GPU 或跨实例的通信、负载平衡和扩容开销。
| 扩展方向 | 新增约束 | 需要补充的证据 | 后续入口 |
|---|---|---|---|
| Tensor / Pipeline / Expert Parallel | 分片、同步和负载平衡 | 通信时间、空转、吞吐、显存 | 79–81、分布式专题 |
| MoE Expert Parallel | token dispatch、专家容量和负载不均 | expert load、通信时间、空转、吞吐 | Part 01 · 22、79–81 |
| PD 多实例 | 跨池传输和池间负载不均 | transfer time、池利用率、P99 | 38、70 |
| 自动扩缩容 | 冷启动、迁移和容量预测 | 扩容延迟、恢复时间、拒绝率 | 性能分析与部署专题 |
参考入口:开源项目 vLLM 与 SGLang;论文 SGLang 和官方文档 PD Disaggregation。
判断框架
本节承接 04 的 Cache 资源边界,先阅读 37 KV Cache Scheduling 和 38 Prefill / Decode Disaggregation,再通过 70 Serving Scheduler Benchmark 观察真实请求 workload。阅读下表时,先固定请求分布、Prompt 长度、generated tokens、并发度、batch 策略和 Cache policy,再区分计算、排队与资源分配问题。
| 观察到的现象 | 优先判断 | 下一步 |
|---|---|---|
| 长 Prompt 到达后 Decode 请求明显抖动 | Prefill 抢占或批次组织不合理 | 检查 Chunked Prefill 和 Continuous Batching |
| TTFT 可接受但 TPOT / P99 变差 | Decode 资源被挤占或排队积累 | 检查 Decode 调度和资源配额 |
| 单实例无法同时满足两类请求 | Prefill 与 Decode 资源需求不同 | 评估 PD 分离 |
| GPU 利用率低但排队时间高 | 调度粒度、批次或跨实例通信不合理 | 进入 profiling 和 serving benchmark |
