λLLM Wiki

SGLang Scheduler

SGLang 调度器(SGLang Scheduler)sglang 里负责“选哪些请求上 GPU、何时 prefill、何时 decode、何时回收 cache”的核心运行时组件。

它在解决什么问题

  • 推理请求到达的速度和长度都不一致,但 GPU 显存是硬约束。
  • 如果调度太保守,吞吐会低;如果调度太激进,就会 OOM 或频繁回撤。
  • 因此 scheduler 的目标不是简单排队,而是在显存约束下持续逼近最大有效吞吐。

核心批次状态

SGLang 的调度主线可以理解成四个状态:

  • waiting_queue:等待进入 GPU 的请求。
  • new_batch:准备做 prefill / extend 的请求。
  • running_batch:已经进入 decode 阶段、后续会持续生成的请求。
  • cur_batch:当前这一轮真正送去 forward 的 batch。

这个拆分的意义是:prefill 和 decode 的资源形态不同,scheduler 必须显式区分。

关键实现思路

1. continuous batching

  • scheduler 不会等一个 batch 全部结束再接下一批。
  • 只要某些请求完成,就把它们移出;只要资源允许,就把新请求补进来。
  • 这就是 连续批处理(Continuous Batching),也是高吞吐 LLM serving 的基础。

2. prefill-first 调度

  • SGLang 的策略更偏向 prefill 优先。
  • 如果新请求到来,系统会在当前 decode 轮结束后,优先插入一次 prefill,把这些请求尽快转换成可持续 decode 的状态。
  • 这样做主要是为了改善 首 token 时间(Time To First Token, TTFT),避免新请求长期饿死。

3. decode 阶段的内存检查与回撤

  • decode 前会先检查当前 batch 是否还有足够的 KV 空间。
  • 如果不够,系统会先尝试驱逐没有被活跃请求引用的 cache。
  • 还不够的话,就会执行更激进的 retract,把部分请求退回 waiting_queue,等后面再继续。

为什么它和 KV cache 绑得很紧

  • scheduler 真正调度的不是“文本长度”,而是可用的 KV 容量和 prefix 可复用程度。
  • 这也是为什么它必须理解 ReqToTokenPoolTokenToKVPool、radix cache 这些结构。
  • 换句话说,sglang-scheduler 的批处理策略,本质上是建立在 kv-cache 管理机制之上的。

三个最重要的优化

1. prefix-aware 调度

  • 如果多个请求共享很长前缀,那么先调它们能减少重复 prefill。
  • 因此 SGLang 会基于最长前缀匹配对 waiting queue 重新排序。
  • 这是一种“调度服从 cache 命中率”的思路。

2. in-batch prefix caching

  • 即使某个请求在全局 cache 中前缀不长,它也可能和当前 batch 里的其他请求很像。
  • 此时系统会临时降低一部分请求优先级,只先跑其中一个,让后续请求复用它刚算出的前缀。
  • 这是一种为了未来命中率,主动牺牲当前并行度的小策略。

3. 类 TCP 的拥塞避免

  • new_token_ratio 用来估计“未来还会生成多少 token”,从而控制 admission 的激进程度。
  • decode 成功时,scheduler 会逐步放宽估计,扩大 batch。
  • 一旦接近 OOM,就重新变保守。
  • 这和网络里的拥塞窗口非常像,都是在动态试探系统极限。

一个简化理解

  • prefill 像“把请求送上车”。
  • decode 像“让已经上车的请求继续跑”。
  • scheduler 的工作就是一边别让新乘客等太久,一边别把车塞爆。

相关页面

  • 运行时上下文复用见 kv-cache
  • 服务侧实体介绍见 sglang
  • 如果把它放到 RL rollout 里理解,可结合 multi-turn-rl 一起看。

Comments