先说结论
SGLang 之所以吞吐高,不是因为它只做了“快推理”,而是因为它把在线服务里最贵的几个环节都做了系统级优化:请求怎么进入、怎么合批、怎么复用 prefix、怎么组织 KV cache、怎么选 attention kernel、怎么降低 launch overhead、怎么在 decode 阶段少走弯路。
把 prefix 复用做成一等公民
很多线上请求并不完全独立。系统提示词、聊天模板、RAG 前缀、agent tool scaffolding 都会重复。SGLang 直接把 prefix 复用放到 runtime 中心,而不是事后补丁。
让调度器决定 GPU 的忙碌方式
高吞吐不是“模型单步快”,而是“GPU 每一步都在干最值钱的活”。SGLang 的 scheduler 决定哪些请求进 batch、prefill 和 decode 怎么穿插、缓存怎么命中、草稿模型怎么协同。
把软硬件细节都吃干榨尽
它同时利用 FlashInfer、Triton、自定义 backend、CUDA Graph、分块 prefill、speculative decoding、不同并行策略和大量 launch 参数,把“理论性能”尽量变成“稳定吞吐”。
系统架构
从代码结构看,SGLang 的 serving runtime 不是一个薄 HTTP 壳子,而是一套完整的在线推理执行系统。入口有 HTTP server,核心有 tokenizer / scheduler / model runner / attention backend / KV cache / speculative worker 等模块。
入口层:HTTP Server
HTTP 入口负责协议兼容和请求接入。官方 bench 文档明确区分了在线 benchmark(经过 HTTP server 和 scheduler)与离线 benchmark(直接走 Engine / ModelRunner),这也说明 SGLang 很清楚“HTTP、调度、模型执行”是不同层级的成本。
编排层:Scheduler
源码里 scheduler.py 直接写明它是 “A scheduler that manages a tensor parallel GPU worker.”。它不是配角,而是 serving runtime 的大脑。这里还直接引入了 RadixCache、调度策略模块、以及 speculative decoding 相关类型。
执行层:ModelRunner
model_runner.py 顶部说明非常直白:ModelRunner runs the forward passes of the models. 也就是说,Scheduler 决定做什么,ModelRunner 负责把这件事在 GPU 上真正跑出来。
Kernel 层:多 attention backend
在 flashinfer_backend.py 顶部,SGLang 直接写了:现在有 FlashInfer 和 Triton 两类 backend,FlashInfer 更快,Triton 更容易定制;而且 prefill 和 decode 是分开优化的。
一条请求在 SGLang 里怎么跑
理解这条链路,你就知道它为什么快。核心就是:在进入 GPU 之前就尽量做好组织,在进入 GPU 之后尽量避免重复算。
SGLang 的精髓
如果只记三个词,我会选:prefix-aware、scheduler-centric、kernel-pragmatic。
精髓一:把“程序结构”变成“服务结构”
SGLang 最早不是只想做一个 server,而是想让 LLM generation 有更强的结构表达能力。这件事延伸到 serving,就自然走向 prefix 复用、约束生成、批量管理、多请求共享执行状态。它不是把模型 API 包一层,而是在重写“请求应该怎样组织”。
精髓二:prefill 和 decode 分开看
很多系统把“推理”当成一件事,但 SGLang 很清楚 prefill 与 decode 的瓶颈不同、最优 kernel 不同、调度方式也不同。官方 attention backend 文档式源码就写明:backend 同时支持 extend(带 cached prefix 的 prefill)和 decode,两者分别优化。
精髓三:高性能不是单点,而是整条链
在线推理会被很多小损耗拖死:host-to-device copy、kernel launch、KV 分配、批次抖动、无谓 prefill、低 accept-rate 的 speculative path。SGLang 的设计很明显是在削这些边角料,让每个阶段都别拖后腿。
精髓四:工程上非常务实
它不执着一种 backend。FlashInfer 快就用 FlashInfer,Triton 好改就保留 Triton;能开 CUDA Graph 就开;不适合就切换;launch 参数多到像赛车调教台,因为他们追求的是现实机器上的最优解,不是论文里的整洁感。
它怎么做到这么高的吞吐
下面这些因素叠起来,才构成 SGLang 的高吞吐。少一个点,它都还是快;但真正可怕的是它把这些点串成了一套组合拳。
Prefix / KV Cache 复用
Scheduler 里直接依赖 RadixCache。这意味着 prefix 命中不是外围特性,而是核心调度路径的一部分。共享 system prompt、相同模板、类似上下文的请求,能跳过大量重复 prefill。
动态批处理把 decode 做厚
高并发服务时,decode 阶段往往是长期主战场。SGLang 通过调度器不断把活跃请求拼成合适 batch,让 GPU 在每一步 decode 里处理尽可能多 token,而不是被很多小请求打碎。
把 prefill 和 decode 用不同实现打磨
FlashInfer backend 顶部直接说明:它区分 extend 和 decode;Triton backend 也专门为 forward metadata、kv splits、窗口化 attention 等准备不同逻辑。阶段分治本身就是吞吐来源。
Paged KV / 分页式 attention 执行
从 FlashInfer backend 中出现的 BatchDecodeWithPagedKVCacheWrapper、BatchPrefillWithPagedKVCacheWrapper 就能看出,SGLang 明确围绕分页 KV cache 设计 attention 执行路径。这让长上下文和动态 batch 更可控。
CUDA Graph 降低 launch overhead
ModelRunner 和多个 runtime 路径都集成了 CUDA graph / piecewise graph。对稳定批次和重复图来说,这能明显减少 CPU 发射 kernel 的开销,尤其是在小步 decode 高频调用时很值钱。
Speculative Decoding 提高有效输出速度
Scheduler 里直接解析 SpeculativeAlgorithm,并在初始化时启动 model worker 与 draft worker。也就是说 speculative decoding 不是外围插件,而是主路径能力。accept length 越好,真实吞吐就越高。
Kernel backend 可切换,贴硬件调优
FlashInfer 更快,Triton 更可定制,这是源码直接写出来的取舍。SGLang 不赌单一路线,而是让 runtime 根据模型、硬件、功能需求走最合适 backend。
大量 launch 参数暴露真实性能旋钮
官方 server arguments 文档里,和并行、memory、chunked prefill、attention backend、speculative、hybrid kvcache ratio、load watch 等相关的参数非常多。说明团队把性能当成“可调系统”,不是黑盒。
在线 benchmark 体系很完整
bench_serving 会直接测 TTFT、ITL、吞吐、端到端延迟,还会在 SGLang 场景下查询 /get_server_info 报 speculative accept length。能持续测,才能持续压性能。
高吞吐的底层逻辑,可以压缩成一个公式
吞吐 ≈ 更少重复计算 + 更少 GPU 空转 + 更少 launch 开销 + 更高 batch 利用率 + 更高 cache 命中率 + 更高 speculative accept 效率。
你会发现,SGLang 的每个核心模块几乎都在为这几个项服务。
| 瓶颈 | SGLang 的应对 | 为什么有效 |
|---|---|---|
| 相同前缀重复 prefill | RadixCache / prefix reuse | 直接省掉最贵的一段算力和内存流量 |
| 请求碎片化导致 batch 太小 | scheduler 动态合批 | 提高每步 decode 的有效 token 数 |
| prefill / decode 瓶颈不同 | 分阶段 backend 和元数据组织 | 每个阶段各用最优路径 |
| KV cache 管理混乱 | Paged KV + allocator | 更适合长上下文和动态请求生命周期 |
| kernel launch 太频繁 | CUDA Graph / piecewise graph | 降低 CPU 发射与图构建成本 |
| decode decode 每步只出一个 token 太慢 | speculative decoding | 高 accept 时显著提升有效输出速率 |
| 不同硬件最优路径不同 | FlashInfer / Triton / 多 backend | 避免单一路径吃遍所有场景 |
生产环境怎么证明它真的快
不是看一句“我们很高效”,而是看它能不能稳定把关键指标吐出来。SGLang 这点做得也挺完整。
Benchmark 分层很清楚
bench_serving:走 HTTP server 和 scheduler,最接近真实线上。bench_one_batch_server:测单批次端到端延迟,含 HTTP 和调度开销。bench_offline_throughput:绕开 HTTP,直测 Engine 级最大吞吐。bench_one_batch:更接近 kernel / 单静态 batch 剖析。
可观测指标不只吞吐
- TTFT(首 token 时间)
- ITL / TPOT(token 间延迟)
- 端到端请求延迟
- prompt / generation token 总量
- 推测解码 accept length
- Prometheus 指标与 Grafana 面板
引用与依据
下面这些说法都尽量落在可见文档或源码上,不吹玄学。
python/sglang/srt/managers/scheduler.py:14 写明 “A scheduler that manages a tensor parallel GPU worker.”;同文件引入 RadixCache(约第 183 行)和 SpeculativeAlgorithm(约第 201 行)。python/sglang/srt/model_executor/model_runner.py 顶部注释写明 “ModelRunner runs the forward passes of the models.”python/sglang/srt/layers/attention/flashinfer_backend.py 顶部说明:FlashInfer 更快,Triton 更易定制;都支持 extend 与 decode。BatchDecodeWithPagedKVCacheWrapper、BatchPrefillWithPagedKVCacheWrapper。