Skip to content

调度系统 — 概念

连续批处理(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 延迟清理的请求,确保调度器不会过早认为"无请求"。异步调度 + PD KV consumer 场景下,请求完成时其 KV 块可能仍被在途(in-flight)的 step 引用,调度器现在将这些块的释放延迟到所有在途 step 完成后才执行,避免提前释放导致的 use-after-free。

前缀缓存与混合注意力

Marconi 式混合缓存准入

针对混合 KV 缓存(如含 Mamba / 线性注意力层),HybridKVCacheCoordinator 计算 num_uncached_common_prefix_tokens(其他 group 缓存了更长前缀,表明存在跨请求的未缓存公共前缀)。调度器据此优先把 prefill token 数截断为该公共前缀长度(按 block_size 对齐),加速公共前缀入缓存。

部分前缀缓存原语(Partial Prefix Cache)

BlockPool 新增 block→hash 反向索引(cached_block_hashes_by_block)与部分块提升机制,支持同一缓存块从 partial 状态提升为 full,为异构 block_size 与跨 group 缓存复用铺路。

稀疏保留间隔(Retention Interval)

对 sliding-window KV(DeepSeek V4)与 Mamba / 线性注意力,新增 VLLM_PREFIX_CACHE_RETENTION_INTERVAL:按固定间隔保留稀疏缓存检查点块(须为 block_size 倍数),而非密集缓存全部 token,节省显存。Mooncake 连接器同步支持该保留间隔。

请求队列与优先级

调度器维护多个请求队列:

队列用途
waiting等待 prefill 的新请求
running正在 decode 的活跃请求
swapped被交换到 CPU 的请求

调度优先级:

  1. 处理 swapped 队列(恢复被抢占的请求)
  2. 继续 running 队列的 decode
  3. 从 waiting 队列添加新 prefill

队列准入(server 级背压)

max_num_seqs 限制的是单个引擎/DP rank 内的并发;v0.26.1rc0 后新增 server 级准入控制(#49445):--max-num-queued-reqs(未完成请求总数上限)与 --max-num-queued-tokens(prefill 中请求的 prompt token 总量上限,可视为 TTFT QoS 阀门)在 API server 进程判定(AsyncLLM.check_admission(),计数来自前端 OutputProcessor,无需引擎往返),超限返回 HTTP 503 让 LB 换实例重试——调度器自身无感知。容量建议 data_parallel_size × max_num_seqs + 期望队列深度(#55124)。详见 topics/serving/concepts

调度器本体的近期修复:PRIORITY 策略静默跳过请求(#49206)、P/D 分离下的抢占竞态(#50297)、num_output_placeholders 抢占下溢(#48245)、spec decode 不再把 batch pad 到 max_model_len(#53962)、推测解码 token 预算自适应(#51725,Kimi K3 DSpark 场景 TTFT 降约 60%)。

调度决策流程

调度配置参数

参数默认值含义
max_num_seqs128(SchedulerConfig);API/LLM 上下文下因 GPU 而异(如 H100 上 1024)最大并发序列数
max_num_batched_tokens2048(SchedulerConfig);API/LLM 上下文下因 GPU 而异(H100 上可达 8192/16384)每轮迭代最大 token 数
max_model_len模型默认最大序列长度
enable_chunked_prefillTrue是否启用 chunked prefill
scheduling_policy"fcfs"调度策略(先来先服务/优先级)
watermark0.0KV cache 水位线(占比)。>0 时接纳 waiting/preempted 请求会保留该比例空闲块作缓冲,减少显存紧张时频繁抢占-驱逐抖动;不影响已在运行的 decode
prefill_schedule_interval1DP 部署下每 N 步才 admit 新 prefill,跨 rank 对齐节奏,避免某些 rank 长时间做 prefill 拖慢集合通信
max_num_queued_reqsNone(不限制)server 级未完成请求上限(API server 准入,#49445)
max_num_queued_tokensNone(不限制)server 级 prefill token 总量上限(API server 准入,#49445)

相关概念