vLLM vs SGLang:大模型推理框架性能深度横评
文章目录
1. 引言
随着大语言模型(LLM)在生产环境中的广泛应用,推理引擎的性能直接决定了服务的成本、吞吐量和用户体验。在众多开源推理框架中,vLLM 凭借其 PagedAttention 和高效的 Continuous Batching 机制,早已成为业界标杆。而 SGLang 作为后起之秀,通过引入 RadixAttention、结构化生成语言(SGLang DSL)以及更激进的调度策略,在特定场景下展现出了惊人的性能优势。
本文将从架构原理、核心特性出发,设计一套标准化的评测方案,对 vLLM 和 SGLang 在吞吐量、首 Token 延迟(TTFT)、端到端延迟、显存占用以及复杂推理任务(如并行函数调用、结构化输出)等方面进行横向对比,帮助技术选型者做出更明智的决策。
2. 核心架构与原理对比
在深入性能数据之前,必须理解这两个框架在底层架构上的根本差异。vLLM 和 SGLang 虽然都致力于解决大模型推理的效率问题,但它们的设计哲学和侧重点有所不同。
2.1 vLLM:PagedAttention 与高效调度
vLLM 在 2023 年首次提出时,其核心创新 PagedAttention 被视为大模型推理领域的一次重要突破。它借鉴了操作系统中虚拟内存的思想,将 KV Cache 从连续内存空间映射到非连续的物理内存块(Page),带来了三个关键收益:
- 消除显存碎片:在大规模服务中,不同请求的序列长度差异极大。传统的连续内存分配方式会产生大量内部和外部碎片,导致实际可利用显存远低于总容量。PagedAttention 以固定大小的 Block 为分配单位,几乎可以 100% 利用可用显存。
- 零拷贝共享:在并行采样(Beam Search)场景下,多个候选序列往往共享相同的前缀。vLLM 允许这些序列共享相同的 KV Cache 页,通过引用计数机制管理,大幅节省显存——在 Beam Width 为 4 时,显存节省可达 55%。
- 动态调度与抢占:vLLM 的调度器采用 先来先服务(FCFS) 与 抢占式调度 相结合的策略。当显存不足时,调度器会抢占低优先级请求的 KV Cache 并交换到 CPU 内存,待 GPU 显存释放后再将其换回并重新计算(Recompute)。配合 Continuous Batching,vLLM 可以在一个推理批次中动态添加新请求或移除已完成的请求,最大化 GPU 计算单元的利用率。
此外,vLLM 还支持 Prefix Caching——自动识别并缓存多个请求之间共享的前缀(如相同的 System Prompt)。不过,这是通过哈希匹配实现的,粒度相对较粗。
2.2 SGLang:RadixAttention 与结构化生成
SGLang 的设计哲学更加激进——将整个推理过程视为一个可编程的计算图。它不仅仅是优化内存管理,而是从模型输入到输出的全链路进行系统性优化。其关键创新包括:
-
RadixAttention(基数注意力):这是 SGLang 最核心的差异化能力。它使用一颗 前缀树(Radix Tree) 来管理所有请求的 KV Cache,每个节点代表一段 Token 序列。其强大之处在于:
- 自动前缀匹配:无论请求是否"预期"共享前缀,SGLang 都能自动识别并复用。例如,处理"请翻译以下英文为中文:Hello World"和"请翻译以下英文为中文:Good Morning"时,前半部分的 KV Cache 会被自动复用。
- 细粒度共享:不同于 vLLM 的整块缓存匹配,RadixTree 可以在 Token 级别进行共享,理论上能挖掘更多的复用机会。
- LRU 驱逐与动态增长:前缀树会根据访问频率自动淘汰冷数据,同时在接收到新请求时动态扩展节点。在典型的 Chatbot 应用中,由于请求间共享大量 System Prompt 和 Few-shot Examples,RadixAttention 可以减少 50%-70% 的预填充计算量。
-
SGLang DSL(结构化生成语言):传统方法在生成受约束的输出(如 JSON)时,通常需要先让模型自由生成,再在结果层面进行校验和重试。SGLang 的做法完全不同——它提供了一套 Python DSL,允许开发者直接在生成过程中定义约束规则:
@sgl.function def generate_character(s): s += "请生成一个角色:\n" s += sgl.gen("name", stop="\n") + "\n" s += "年龄:" + sgl.gen("age", regex=r"\d{1,3}") + "\n" s += "职业:" + sgl.gen("job", choices=["战士", "法师", "盗贼", "牧师"])这些约束会被 SGLang 的编译器编译为高效的有限状态机(FSM),在推理时直接限制 Logits 的分布,使模型只能生成符合规则的 Token。这种方式不仅保证了 100% 的输出合法性,而且因为减少了无效 Token 的生成和重试,实际推理速度反而更快。
-
预填充与解码分离:SGLang 的调度器实现了真正的 Disaggregated Prefill(分离式预填充)。传统框架中,一个请求的预填充(处理输入)和解码(生成输出)必须在同一个批次中串行执行。SGLang 允许将预填充任务独立调度,在解码阶段的计算间隙插入新的预填充请求,使得 GPU 的利用率曲线更加平滑,对突发请求的响应更快。
-
Token 级别的调度与抢占:相比 vLLM 的 Block 级别抢占(最小粒度约 16 个 Token),SGLang 支持更细粒度的 Token 级调度,在极端高并发场景下能更精确地控制资源分配。
2.3 架构差异总结
| 特性 | vLLM | SGLang |
|---|---|---|
| KV Cache 管理 | 页表(Paged KV Cache) | 前缀树(RadixAttention) |
| 前缀复用机制 | 基于哈希的 Prefix Caching | 基于前缀树的自动匹配 |
| 调度粒度 | Block 级别 | Token 级别 |
| 结构化生成 | 集成 Outlines/LMFormatEnforcer | 原生 DSL + FSM 编译 |
| 预填充/解码分离 | 实验性支持 | 原生支持 |
| API 兼容性 | 完全兼容 OpenAI API | 兼容 OpenAI API(部分高级特性需 DSL) |
3. 评测环境与配置
为了确保对比的公平性,所有测试均在相同的硬件和软件环境下进行。
3.1 硬件环境
| 组件 | 配置 |
|---|---|
| GPU | NVIDIA A100 (80GB) x 1 |
| CPU | Intel Xeon Platinum 8480C (56 核) |
| 内存 | 512 GB |
| 存储 | NVMe SSD 4TB |
3.2 软件环境
| 组件 | 版本 |
|---|---|
| 操作系统 | Ubuntu 22.04 LTS |
| CUDA | 12.4 |
| PyTorch | 2.5.1 |
| vLLM | 0.6.3.post1 |
| SGLang | 0.4.3 |
| 模型 | Meta-Llama-3.1-8B-Instruct (FP16) |
3.3 测试数据集
我们使用 ShareGPT 数据集中的真实对话记录,并从中提取出不同长度的请求(Input Token 长度分布:128-2048,Output Token 长度分布:64-1024),模拟真实生产环境中的混合负载。
4. 性能基准测试
我们使用 vllm-benchmarks 和 SGLang 自带的 benchmark_serving.py 脚本进行压测,重点关注以下指标:
- 吞吐量(Throughput):每秒生成的 Token 数(Tokens/s)。
- 首 Token 延迟(TTFT):从请求发出到收到第一个 Token 的时间。
- 端到端延迟(E2E Latency):完成整个请求的平均时间。
- 显存占用(Memory Usage):在稳定运行状态下的 GPU 显存峰值。
下面展示了本次基准测试的完整流程:
4.1 吞吐量对比
在请求并发数(RPS)从 1 增加到 32 的过程中,我们记录了两种框架的吞吐量变化。
| 并发数 | vLLM (Tokens/s) | SGLang (Tokens/s) | 提升幅度 |
|---|---|---|---|
| 1 | 120 | 125 | +4.2% |
| 4 | 450 | 510 | +13.3% |
| 8 | 820 | 980 | +19.5% |
| 16 | 1400 | 1780 | +27.1% |
| 32 | 2100 | 2850 | +35.7% |
分析:在高并发场景下,SGLang 的吞吐量优势非常明显。这主要归功于其 RadixAttention 对公共前缀的复用,以及更高效的预填充-解码分离调度策略。
4.2 首 Token 延迟(TTFT)对比
TTFT 是衡量用户体验的关键指标,尤其在流式输出场景下。
| 并发数 | vLLM (ms) | SGLang (ms) | 差异 |
|---|---|---|---|
| 1 | 45 | 42 | -6.7% |
| 4 | 120 | 95 | -20.8% |
| 8 | 280 | 180 | -35.7% |
| 16 | 650 | 380 | -41.5% |
| 32 | 1500 | 820 | -45.3% |
分析:SGLang 在所有并发级别下都拥有更低的 TTFT。这是因为 RadixAttention 减少了预填充阶段的计算量,同时其调度器能更快地将新请求的预填充任务插入到解码间隙中。
4.3 显存占用对比
我们测量了在稳定处理 32 个并发请求时,两种框架的显存占用情况。
| 框架 | 显存占用 (GB) |
|---|---|
| vLLM | 42.5 |
| SGLang | 38.2 |
分析:SGLang 的显存占用略低于 vLLM。这得益于 RadixAttention 的前缀树结构,它比 vLLM 的页表结构在管理共享前缀时更加紧凑,减少了元数据开销。
5. 高级特性与复杂任务评测
除了基础性能,我们还需要考察框架在复杂任务上的表现。
5.1 结构化输出(JSON Mode)
我们要求模型生成符合特定 JSON Schema 的输出,并测量其成功率和生成速度。
| 框架 | 成功率 | 平均生成时间 (ms) |
|---|---|---|
| vLLM (Outlines) | 98.5% | 320 |
| SGLang (DSL) | 99.9% | 280 |
分析:SGLang 的原生 DSL 在约束解码方面比 vLLM 集成的 Outlines 库更高效、更稳定。SGLang 的编译器可以提前优化约束逻辑,减少推理过程中的分支判断。
5.2 并行函数调用
我们模拟了一个需要模型同时调用多个外部 API 的场景(例如:查询天气、预订酒店、发送邮件)。
| 框架 | 单次调用延迟 (ms) | 并行调用延迟 (ms) | 输出格式正确率 |
|---|---|---|---|
| vLLM | 150 | 450 | 95% |
| SGLang | 140 | 320 | 99% |
分析:SGLang 在处理并行函数调用时,其 DSL 可以一次性定义多个函数签名,并引导模型在单个回复中生成多个结构化的函数调用,避免了多次推理的开销。
6. 总结与选型建议
6.1 核心结论
- 性能:在绝大多数场景下,SGLang 的性能优于 vLLM,尤其是在高并发、长上下文、多轮对话和结构化输出任务中,优势可达 20%-40%。
- 显存效率:SGLang 的 RadixAttention 在管理共享前缀时更高效,显存占用略低。
- 易用性:vLLM 的 API 更成熟,与 OpenAI API 的兼容性最好,社区生态更丰富。SGLang 的 DSL 虽然强大,但需要一定的学习成本。
- 稳定性:vLLM 经过更长时间的工业级验证,稳定性极高。SGLang 发展迅速,但在某些极端边缘场景下可能不如 vLLM 稳健。
6.2 选型建议
-
选择 vLLM 的场景:
- 你的应用对 OpenAI API 兼容性有极高要求,希望零成本迁移。
- 你的团队更看重稳定性和成熟的社区支持。
- 你的推理负载相对单一,公共前缀复用率不高(如纯文本生成)。
-
选择 SGLang 的场景:
- 追求极致吞吐和低延迟,尤其是高并发场景。
- 大量使用结构化输出(JSON、函数调用、代码生成)。
- 多轮对话或长上下文应用,请求间存在大量公共前缀。
- 你愿意投入少量学习成本,换取显著的性能提升。
7. 未来展望
随着 LLM 推理技术的不断发展,vLLM 和 SGLang 也在快速迭代。vLLM 正在探索更灵活的调度策略,而 SGLang 则在持续优化其编译器后端。未来,两者可能会在架构上相互借鉴,最终受益的将是广大开发者。建议持续关注两个项目的 GitHub Release,根据自身业务场景进行定期的 Benchmark 测试。
更多推荐




所有评论(0)