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 可复用程度。
- 这也是为什么它必须理解
ReqToTokenPool、TokenToKVPool、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