Appearance
调度系统 — 概念
连续批处理(Continuous Batching)
传统静态批处理中,一个 batch 内所有请求必须全部完成才能开始新 batch。Continuous Batching 打破了这个限制:
关键优势:
- 更低的延迟:新请求无需等待整个 batch 完成
- 更高的吞吐:GPU 始终保持满载
- 更公平的调度:短请求不会被长请求阻塞
Chunked Prefill
长 prompt 的 prefill 可能非常耗时(占用大量计算资源和显存)。Chunked Prefill 将 prefill 分成多个 chunk:
好处:
- 降低 TTFT:不需要一次性处理完整个 prompt
- 混合调度:prefill 和 decode 可以在同一轮迭代中混合执行
- 显存友好:每次只需分配部分 prompt 的 KV 缓存
Preemption 策略
当显存不足以容纳所有活跃请求的 KV 缓存时,调度器会触发 preemption:
1. Re-computation(重新计算)
直接丢弃被抢占请求的 KV 缓存块。当请求恢复时,重新计算 prefill。适用于抢占时间短的场景。
2. Swapping(交换到 CPU)
将 KV 缓存块从 GPU 交换到 CPU 内存。恢复时再交换回来。适用于抢占时间较长的场景。
3. 异步抢占多帧丢弃
当使用推测解码或流水线并行时,被抢占请求可能还有多个在途(in-flight)的输出帧。旧的实现使用布尔标志只能丢弃一帧,新的计数器机制逐帧正确排空:
discard_latest_async_tokens (bool) → async_tokens_to_discard (int counter)调度器将 async_tokens_to_discard 设为 num_output_placeholders,异步调度器每帧递减计数器,确保所有在途帧被正确排空后才恢复请求。
4. KV Connector 延迟释放
KV Connector 的异步操作可能在请求从调度队列移除后仍在进行。has_finished_requests() 现在额外检查 self.requests 中是否还有等待 KV connector 延迟清理的请求,确保调度器不会过早认为"无请求"。
请求队列与优先级
调度器维护多个请求队列:
| 队列 | 用途 |
|---|---|
| waiting | 等待 prefill 的新请求 |
| running | 正在 decode 的活跃请求 |
| swapped | 被交换到 CPU 的请求 |
调度优先级:
- 处理 swapped 队列(恢复被抢占的请求)
- 继续 running 队列的 decode
- 从 waiting 队列添加新 prefill
调度决策流程
调度配置参数
| 参数 | 默认值 | 含义 |
|---|---|---|
max_num_seqs | 256 | 最大并发序列数 |
max_num_batched_tokens | 8192 | 每轮迭代最大 token 数 |
max_model_len | 模型默认 | 最大序列长度 |
chunked_prefill_enabled | True | 是否启用 chunked prefill |
scheduling_policy | "fcfs" | 调度策略(先来先服务/优先级) |
相关概念
- Paged Attention — KV 缓存块的管理方式
- KV Cache — KV 缓存的基本概念
- Continuous Batching — 连续批处理的详细原理
- Prefix Caching — 共享前缀的 KV 缓存复用