Skip to content

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 扩大可复用状态的范围 ​

层级位置获得什么多付出什么
L1GPU 显存直接访问,延迟低容量小、昂贵
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 与分离部署。

别急,先让缓存热一下。