09. SGLang 的执行机制
本篇导读
上一篇从 vLLM 看到了引擎模块的协作。本篇换到 SGLang,继续追问同一份制度被反复阅读时,计算状态怎样共享。先看多条请求如何合并成树,再看活跃引用、淘汰、分层缓存和结构化生成;最后与 vLLM 的完整块索引对应。
SGLang 最初把描述生成任务的 frontend language 与高效 runtime 放在一起设计。今天可以直接通过兼容 API 使用 runtime,不必先学习 DSL。它和 vLLM 都已具备广泛的服务能力,差异要落到目标模型、状态管理与执行路径上。
它的经典切入点是共享前缀:大量请求重复系统提示、多轮历史或同一文档时,如何把已经算过的状态组织起来,让后续请求找到并安全复用。
压缩前缀树怎样组织请求
上图三条教学序列分别为 a b c d e f、a b c d x y、a b m n。A、B 共享更长前缀,C 更早分叉。对应到资料助手,稳定的提示和相同制度可能形成共享路径,变化的问题产生分支;实际匹配仍是 token,不能按文档标题或语义直接判断。
普通逐 token 树可能每个 token 一个节点;压缩树把未分叉的连续路径压在一条边上。新请求沿边匹配,直到首次不同,必要时拆边和建立分支。
RadixAttention 组织的是前缀状态复用,不是在改变模型的注意力语义。树节点维护索引、设备状态位置与引用关系,真正的 KV 由内存池和后端管理。页大小和模型结构仍限制实际可复用粒度,不能把树理解成“任何模型都能任意 token 级命中”。
活跃请求与淘汰
请求命中前缀后,需要锁定或增加活跃引用,防止正使用的状态被回收。请求结束则解除占用;容量紧张时,策略从可淘汰候选中选择。
默认 LRU 倾向保留最近使用的前缀,文档也提供 LFU、SLRU、priority 等策略。候选受到依赖约束:活跃锁定的状态不能随意删,仍有 KV 子节点依赖的父节点也不能直接当独立页回收。常从可回收叶节点开始,之后父节点才可能成为候选。
换淘汰策略改变的是保留偏好,无法增加物理容量。热点工作集超过显存时,命中率仍可能很低,甚至发生反复换入。
Overlap scheduler 隐藏 CPU 空隙
当 GPU 计算当前 batch,CPU 提前准备后续调度或元数据,可以减少两次 GPU 工作之间的空闲。它对单步很短、CPU 占比明显的场景可能更有价值。
异步执行意味着状态存在“已经安排”和“真正完成”的差别。取消、推测回滚、递归状态和结构化约束都要遵守依赖,不能把重叠简单理解成多开线程。具体支持组合必须对齐版本。
HiCache 扩大可复用状态的范围
| 层级 | 位置 | 获得什么 | 多付出什么 |
|---|---|---|---|
| L1 | GPU 显存 | 直接访问,延迟低 | 容量小、昂贵 |
| L2 | 主机内存 | 保留更多前缀 | 主机到 GPU 的传输和预取 |
| L3 | 共享或分布式存储 | 跨实例或更大工作集复用 | 网络、存储、布局恢复与一致性 |
HiCache 可与 Mooncake 等后端结合。远端“命中”不是 GPU 本地免费命中:只有加载比重算更划算,才能减少总时间。需要同时观察层级 token 命中、预取是否及时、有效带宽、写回开销和队列。
HiSparse 与 HiCache 不是同一机制。 稀疏访问或驻留优化,与前缀分层存储解决不同问题,支持条件也要分别核对。
结构化生成如何限制下一个 token
给定 JSON Schema、正则或语法后,约束后端跟踪当前合法状态,找出下一步允许的 token,把其他候选屏蔽,再推进解析状态。难点之一是 token 不等于字符:一个 token 可能跨过引号、标点或多个字符。
text
当前输出 + 语法状态
↓
下一步允许 token 集合 → logits mask → 采样 → 更新语法状态语法编译、mask 与状态迁移也有成本,首次请求和复杂 schema 尤其值得单测。引擎可能使用不同约束后端,不能把早期论文的压缩状态机实现套到今天所有路径上。
格式合法不代表事实正确,也不代表可以执行工具。例如合法的退款 JSON,仍需应用校验账户归属、金额、幂等与权限。达到长度上限、取消或异常产生的不完整 JSON,也不能算成功。
最小启动与实测问题
bash
python3.11 -m venv .venv-sglang
source .venv-sglang/bin/activate
python -m pip install 'sglang[all]==0.5.22'
python -m sglang.launch_server \
--model-path Qwen/Qwen3-0.6B \
--host 127.0.0.1 --port 8000 \
--context-length 4096这是 Linux NVIDIA GPU 的学习模板;具体硬件、wheel、驱动和模型路径应先检查支持矩阵。与 vLLM 比较时保持同一权重、模板、采样和负载,不能只比较两条命令的默认输出。
源码阅读优先追踪 tokenizer manager、scheduler、radix cache、request/token pool、model runner、grammar 和 P/D transfer 的职责。围绕“最长前缀如何返回”“分叉怎样拆边”“活跃状态何时解锁”“推测拒绝后怎样恢复”阅读,比只看吞吐宣传更容易理解系统。
本篇回顾
- RadixAttention 用压缩树组织前缀状态复用,树是索引,真实 KV 仍由设备池和后端管理。
- 活跃请求不能被随意淘汰;分层缓存增加容量,也增加加载与传输成本。
- 结构化约束限制合法输出形式,不自动证明事实和业务动作正确。
两套引擎现在都有了具体位置。下一篇继续放大规模:一个工作台不够时,怎样把模型、请求或状态分给多个设备? 进入多卡、MoE 与分离部署。
