利用 vLLM 睡眠模式实现零重载模型切换

17 分钟阅读
嵌入式大模型 (Embedded LLM)

简介

多模型服务难题:你有两个 LLM,它们都能塞进 GPU,但无法同时容纳。传统方案迫使你做出艰难的权衡:

  1. 保持两个模型常驻 → 需要 2 倍显存(昂贵,甚至不可能)
  2. 按需重新加载模型 → 每次切换需要 30-100+ 秒(缓慢,浪费)
vLLM Sleep Mode
vLLM 睡眠模式

vLLM 睡眠模式提供了第三种选择:模型能在几秒内休眠并快速唤醒——既实现了按需加载的效率,又保留了持久化服务的速度。

满足不同需求的两种睡眠级别

  • 级别 1:将权重卸载到 CPU 内存(唤醒速度极快)
  • 级别 2:彻底丢弃权重(唤醒速度接近级别 1,内存占用极低)

这两种级别都比完全重新加载快 18-200 倍,并且能与张量并行 (TP)、流水线并行 (PP) 和专家并行 (EP) 无缝兼容。

为什么睡眠模式优于快速权重加载器

即使权重加载速度极快,每次冷启动仍需支付隐藏成本,而睡眠模式则可避免这些成本。

成本描述快速权重加载器睡眠模式
1. 显存加载时间复制权重到 GPU✅ 已优化✅ 已保留
2. 内存分配器设置CUDA 分配器初始化❌ 每次都需要✅ 已保留
3. CUDA 图捕获记录执行图❌ 每次都需要✅ 已保留
4. GPU 内核 JIT 编译DeepGEMM, FlashInfer, TorchInductor❌ 每次都需要✅ 已保留(经过初始预热)
5. 缓存预热首请求开销❌ 每次都需要⚡ 快速重预热

通过保持进程存活,睡眠模式避免了基础设施(#2-#4)的开销和昂贵的重新初始化。这就是为什么基准测试显示,睡眠模式下的推理速度比冷启动快 61-88%

本文涵盖内容:

  • 横跨多种模型尺寸(0.6B 到 235B)和 GPU(A4000 到 A100)的综合基准测试
  • 深入的技术细节,解释性能提升的原理
  • 关于预热影响和 FP8 量化的消融研究
  • 选择合适的睡眠级别的决策指南

快速入门:使用睡眠模式

在线服务 API

启动两个启用了睡眠模式的 vLLM 服务

# Terminal 1: Start Phi-3-vision
export VLLM_SERVER_DEV_MODE=1
vllm serve microsoft/Phi-3-vision-128k-instruct --enable-sleep-mode --port 8001
 
# Terminal 2: Start Qwen3-0.6B
export VLLM_SERVER_DEV_MODE=1
vllm serve Qwen/Qwen3-0.6B --enable-sleep-mode --port 8002

模型的休眠与唤醒

# Put Phi-3-vision to sleep (Level 2 - minimal RAM usage)
curl -X POST 'localhost:8001/sleep?level=2'
 
# Put Qwen3-0.6B to sleep (Level 2)
curl -X POST 'localhost:8002/sleep?level=2'
 
# Wake up Phi-3-vision for inference
curl -X POST 'localhost:8001/wake_up'
curl -X POST 'localhost:8001/collective_rpc' \
  -H 'Content-Type: application/json' \
  -d '{"method":"reload_weights"}'
 
# IMPORTANT: Reset prefix cache after waking (Level 2 only)
curl -X POST 'localhost:8001/reset_prefix_cache'
 
# Now run inference on Phi-3-vision...
# (your inference requests here)
 
# Put back to sleep when done
curl -X POST 'localhost:8001/sleep?level=2'
 
# Wake up Qwen3-0.6B
curl -X POST 'localhost:8002/wake_up'
# (Level 1 doesn't need reload_weights or reset_prefix_cache)
 
# Run inference on Qwen3-0.6B...

注意:对于级别 2 睡眠,唤醒后必须调用 reload_weightsreset_prefix_cache。级别 1 睡眠不需要这些额外步骤。

警告: 安全性:/sleep/wake_up/collective_rpc/reset_prefix_cache 端点需要设置 VLLM_SERVER_DEV_MODE=1,且应仅在受信任的网络中公开。这些管理端点可能会中断服务,仅适用于训练集群或后端应用等受限环境。

性能概览

让我们看看睡眠模式与传统模型重新加载相比表现如何。

睡眠模式 L1 与无睡眠模式性能对比

下方的交互式图表展示了执行 5 次模型切换的总时间:运行模型 A 推理,切换到模型 B,运行模型 B 推理,然后重复此模式(A→B→A→B→A→B)。

使用睡眠模式:模型在切换间隙休眠/唤醒,保留了基础设施。不使用睡眠模式:每次切换都需要完全重启 vLLM 并重新加载。

模型 A:Qwen3-235B-A22B-Instruct-2507-FP8 (TP=4) | 模型 B:Qwen3-Coder-30B-A3B-Instruct (TP=1)
GPU: A100 | vLLM 0.11.0 | 睡眠级别: 1 | 编译: cudagraph_mode: FULL_AND_PIECEWISE

推理性能提升

除了更快的模型切换外,睡眠模式还提供了更快的推理时间。由于模型在从睡眠中唤醒时已经过预热,它们跳过了影响新加载模型的冷启动开销。

唤醒模式(已预热)与冷启动(刚加载)的推理时间比较。
推理时间 = 预填充 (prefill) + 解码 (decode)(唤醒/加载后的首个请求)。每个请求使用不同的问题以避免缓存,输出限制为 100 个 token。
误差线显示了多次运行中的最小/最大值变化。数值显示在柱状图上。
GPU: A100 | vLLM 0.11.0 | 睡眠级别: 1 | 编译: cudagraph_mode: FULL_AND_PIECEWISE

为什么睡眠模式能提高推理速度

61-88% 的推理加速并不是来自更快的权重加载——而是来自保留了冷启动必须从头重建的昂贵基础设施

睡眠模式保留了什么

组件是否保留?冷启动必须支付的成本
内存分配器 (CuMemAllocator)✅ 是❌ 每次重新初始化
CUDA 图✅ 是❌ 每次重新捕获
进程状态 (Python, CUDA 上下文)✅ 是❌ 每次重启
GPU 内核 JIT 缓存✅ 是(首次预热后)❌ 每次重新编译

关键区别

  • 无睡眠模式:进程卸载即死亡 → 无法从预热中获益

    • 必须重启 Python 进程和 CUDA 上下文
    • 必须重新初始化内存分配器
    • 必须重新捕获 CUDA 图
    • 必须重新进行 JIT 内核编译 (DeepGEMM, FlashInfer, TorchInductor)
    • 结果:首次推理慢 4-7 倍(见基准:唤醒 0.92s vs 冷启动 3.72s)
  • 使用睡眠模式:进程保持存活 → 预热产生回报

    • ✅ 分配器、图、进程状态和 JIT 内核在初始预热后全部保留
    • 结果:首次推理保持快速(约 1s),避免了 3-4s 的冷启动惩罚

注意:时间因模型大小、GPU 代际和配置而异。请参阅预热的影响部分,查看详细测量数据,显示未预热时存在 5-7 倍的减速。

模型切换性能

睡眠模式最显著的优势在于模型切换时间。唤醒睡眠中的模型比加载全新的 vLLM 实例快 18-20 倍

模型切换时间:从睡眠唤醒 vs 冷启动(全新加载)。
误差线显示了多次运行中的最小/最大值变化。数值显示在柱状图上。
GPU: A100 | vLLM 0.11.0 | 睡眠级别: 1 | 编译: cudagraph_mode: FULL_AND_PIECEWISE

硬件可扩展性:A4000 GPU 测试结果

睡眠模式的益处不仅限于高端 GPU。这是在 A4000 GPU 上运行较小模型的工作负载,证明了这种性能提升可以在不同硬件层级和模型尺寸间扩展。

模型 A:Qwen3-0.6B | 模型 B:Phi-3-vision-128k-instruct
GPU: A4000 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译: cudagraph_mode: FULL_AND_PIECEWISE

A4000:推理性能

A4000 上的推理时间比较:唤醒模式(已预热) vs 冷启动(刚加载)。
推理时间 = 预填充 (prefill) + 解码 (decode)(唤醒/加载后的首个请求)。每个请求使用不同的问题以避免缓存,输出限制为 100 个 token。
误差线显示了多次运行中的最小/最大值变化。数值显示在柱状图上。
GPU: A4000 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译: cudagraph_mode: FULL_AND_PIECEWISE

A4000:模型切换性能

A4000 上的模型切换时间:从睡眠唤醒 vs 冷启动(刚加载)。
误差线显示了多次运行中的最小/最大值变化。数值显示在柱状图上。
GPU: A4000 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译: cudagraph_mode: FULL_AND_PIECEWISE

A4000 关键观察

  • 推理性能:唤醒模式使 Qwen3-0.6B 的推理速度提升 83%,Phi-3-vision 提升 81%
  • 模型切换:唤醒时间极快(约 0.1-0.8s),对比冷启动实现 58-203 倍加速
  • 总时间节省:62%(5 次切换中 85s vs 226s)
  • 对于小型模型实现近乎即时的切换(0.1s 唤醒时间),使多模型服务体验极其顺滑
  • 证明了睡眠模式在不同 GPU 等级和模型尺寸上均有效

睡眠级别:如何选择合适的模式

vLLM 睡眠模式提供两种级别,各有权衡

级别 1(默认):将模型权重卸载到 CPU 内存,丢弃 KV 缓存

  • 唤醒速度最快(小型模型约 0.1-0.8s,大型模型约 3-6s)
  • 需要足够的 CPU RAM 来存储模型权重
  • 最适合:具有充足 CPU 内存、需要频繁切换模型的系统

级别 2:丢弃模型权重和 KV 缓存,仅在 CPU 中保留缓冲区(如 RoPE 缩放张量等)

  • 唤醒速度较慢(小型模型约 0.8-2.6s),因为需从磁盘重新加载权重
  • CPU RAM 占用极少 - 仅保留小缓冲区
  • 最适合:CPU RAM 有限的系统,或者需要管理无法全部装入内存的大量模型时

性能比较:级别 1 vs 级别 2 vs 无睡眠

模型 A:Qwen3-0.6B | 模型 B:Phi-3-vision-128k-instruct
GPU: A100 (TP=1) | vLLM 0.11.0 | 编译: cudagraph_mode: FULL_AND_PIECEWISE
三种模式对比:级别 1(最快)、级别 2(内存占用最少)、无睡眠。鼠标悬停查看精确时间。

性能总结

模式总时间唤醒时间 (A/B)CPU RAM最适合
无睡眠357.1s不适用(完全重载)极低单模型,无需切换
级别 1112.6s0.26s / 0.82s高(每模型 GB 级别)频繁切换,内存充裕
级别 2124.6s0.85s / 2.58s极低(每模型 MB 级别)内存有限,成本优化

关键洞察

  • 级别 1 最快(比无睡眠快 68%),但需要大量 CPU RAM
  • 级别 2 速度几乎同样快(比无睡眠快 65%),且对 RAM 要求极低
  • 级别 2 的唤醒速度约为级别 1 的 3 倍(以 Qwen3-0.6B 为例,0.85s vs 0.26s),这是由于需要重新加载权重
  • 两种睡眠模式都比无睡眠模式带来了巨大的改进

为什么级别 2 仍然比无睡眠模式快

乍一看这似乎违反直觉:级别 2 从 SSD 重新加载权重(就像“无睡眠模式”一样),那么为什么它整体快了 23-45 倍?

答案:权重加载只是五大成本之一

当你以无睡眠模式重新加载模型时,你需支付所有这些成本

成本级别 2无睡眠模式
1. 权重加载 (SSD → VRAM)❌ 必须支付❌ 必须支付
2. 进程初始化跳过❌ 必须支付
3. 内存分配器设置跳过❌ 必须支付
4. CUDA 图捕获跳过❌ 必须支付
5. GPU 内核 JIT 编译保留(已编译)❌ 全量编译 + 预热

级别 2 策略

  • 从 SSD 重新加载权重(与无睡眠模式相同)
  • 其他全部保留:进程状态、分配器实例、CUDA 图和编译好的 JIT 内核全都完好无损
  • 无需重新编译:内核在初始预热期间已编译并保持在缓存中
  • 每次切换平均耗时:约 2.6s(见上文基准数据)

无睡眠模式现实

  • 从 SSD 重新加载权重(与级别 2 相同)
  • 其他一切重建:进程重启 + 分配器初始化 + 图重新捕获
  • JIT 内核:全量编译 + 显式预热例程 (kernel_warmup() + 虚拟运行)
  • 每次切换平均耗时:约 48s(见上文基准数据)

基准数据证明了一切:对于 5 次模型切换

  • 级别 2:总计 124.6s(平均每次切换约 2.6s)
  • 无睡眠:总计 357.1s(平均每次切换约 48s)

尽管两者都从 SSD 重载权重,但级别 2 整体快了 2.9 倍,因为它保留了昂贵的基础设施(进程状态、分配器、CUDA 图),而这些在无睡眠模式下每次都必须从头重建。

级别 2:推理性能

睡眠级别 2 下的推理时间比较:唤醒模式 vs 冷启动。
推理时间 = 预填充 (prefill) + 解码 (decode)(唤醒/加载后的首个请求)。每个请求使用不同的问题以避免缓存,输出限制为 100 个 token。
误差线显示了多次运行中的最小/最大值变化。数值显示在柱状图上。
GPU: A100 (TP=1) | vLLM 0.11.0 | 睡眠级别: 2 | 编译: cudagraph_mode: FULL_AND_PIECEWISE

级别 2:模型切换性能

睡眠级别 2 下的模型切换时间:从睡眠唤醒 vs 冷启动。
误差线显示了多次运行中的最小/最大值变化。数值显示在柱状图上。
GPU: A100 (TP=1) | vLLM 0.11.0 | 睡眠级别: 2 | 编译: cudagraph_mode: FULL_AND_PIECEWISE

关键观察

指标无睡眠级别 2改进
总时间 (5 次切换)357.1s124.6s快 65%
Qwen3-0.6B 切换时间平均 37.6s平均 0.85s快 45 倍
Phi-3-vision 切换时间平均 58.1s平均 2.58s快 23 倍
Qwen3-0.6B 推理平均 3.67s平均 0.53s快 86%
Phi-3-vision 推理平均 6.30s平均 0.76s快 88%
唤醒时间 vs 级别 1-慢 3-10 倍以 CPU RAM 换取速度

何时使用级别 2

  • CPU RAM 有限:系统无法将所有模型权重保存在 CPU 内存中
  • 成本优化:CPU RAM 较小的廉价云实例
  • 管理多个模型:在内存受限的情况下管理大量模型
  • 仍有显著收益:即使需要重新加载权重,级别 2 也比无睡眠模式快 23-45 倍

级别 1 与级别 2 比较

  • 级别 1:唤醒时间约 0.1-0.8s,每个模型需要约 10-100GB+ CPU RAM
  • 级别 2:唤醒时间约 0.8-2.6s,每个模型仅需约 MB 级别 CPU RAM
  • 两者都比完全重载(约 20-100s)快得多

消融研究

预热对睡眠模式的影响

跳过预热阶段会影响性能吗?预热在初始加载期间预编译 CUDA 图,这可能耗时几秒。我们来对比一下有无预热的情况。

模型 A:Qwen3-0.6B | 模型 B:Phi-3-vision-128k-instruct
GPU: A100 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译: cudagraph_mode: FULL_AND_PIECEWISE
对比有预热(预编译)与无预热(延迟编译)。鼠标悬停查看精确时间。

关键发现

指标有预热无预热差异
初始加载时间108.7s(包含 8.4s 预热)101.1s(无预热)初始节省 7.6s
首次推理 (A)0.45s2.59s无预热慢 5.8 倍
首次推理 (B)0.93s6.61s无预热慢 7.1 倍
后续推理平均 0.43s平均 0.41s无差异
总时间 (5 次切换)119.5s119.0s几乎相同

洞察

  • 预热仅编译内核一次,所有唤醒周期均受益:通过初始预热,JIT 编译和 CUDA 图捕获在加载时执行一次,并保留在后续所有的休眠/唤醒周期中
  • 无预热时,每次唤醒都要支付编译成本:5-7 倍的减速发生在每次唤醒后的首次推理上,而不仅仅是一次
  • 已编译内核在休眠/唤醒间保留:在初始加载期间预热(8.4s)后,所有后续唤醒都有快速的首次推理(0.45s, 0.93s),证明内核已缓存
  • 只需极少预热:单次 1-token 推理足以触发完整 JIT 编译和 CUDA 图捕获,使预热非常廉价
  • 用初始加载时间换取一致性能:8.4s 的预热成本支付一次,即可分摊到所有模型切换中
  • 建议:在生产环境中始终使用预热,以期获得持续、快速的推理体验

量化对睡眠模式的影响

量化 (FP8) 会影响睡眠模式性能吗?我们在 A100 GPU 上使用相同工作负载测试了开启和未开启 FP8 量化的情况。

模型 A:Qwen3-0.6B | 模型 B:Phi-3-vision-128k-instruct
GPU: A100 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译: cudagraph_mode: FULL_AND_PIECEWISE
对比 BF16(基准)与 FP8 量化。鼠标悬停查看精确时间。

消融研究:推理性能(BF16 vs FP8)

推理时间比较:使用睡眠模式下的 BF16 与 FP8 量化。
推理时间 = 预填充 (prefill) + 解码 (decode)(唤醒/加载后的首个请求)。每个请求使用不同的问题以避免缓存,输出限制为 100 个 token。
误差线显示了多次运行中的最小/最大值变化。数值显示在柱状图上。
GPU: A100 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译: cudagraph_mode: FULL_AND_PIECEWISE

消融研究:模型切换(BF16 vs FP8)

模型切换时间:使用睡眠模式下的 BF16 与 FP8 量化。
误差线显示了多次运行中的最小/最大值变化。数值显示在柱状图上。
GPU: A100 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译: cudagraph_mode: FULL_AND_PIECEWISE

关键发现

指标BF16FP8改进
总时间 (5 次切换)108.2s113.6s-5%(稍慢)
Qwen3-0.6B 唤醒时间平均 0.27s平均 0.18s快 33%
Phi-3-vision 唤醒时间平均 0.90s平均 0.78s快 13%
Qwen3-0.6B 推理平均 0.41s平均 0.44s-7%(稍慢)
Phi-3-vision 推理平均 0.81s平均 0.57s快 30%
初始加载时间90.5s96.9s-7%(预热时间更长)

洞察

  • FP8 唤醒操作更快(快 13-33%),这是因为内存移动量减少
  • FP8 改善了较大模型的推理(对于 Phi-3-vision 快 30%),但对微型模型影响微乎其微
  • 由于预热期间的量化开销,FP8 的初始加载时间较长
  • 初始加载后,FP8 通过更快的唤醒周期提供更顺滑的切换
  • 对于频繁切换的工作负载,FP8 更快的唤醒时间可以抵消较长的初始加载时间

决策指南:该使用哪个睡眠级别?

什么情况下使用睡眠级别 1

  • 你有足够的 CPU RAM 来存放所有模型权重
  • 你需要最快的唤醒时间(0.1-6s)
  • 你频繁切换模型(每几秒/分钟)
  • 推理延迟的一致性至关重要

什么情况下使用睡眠级别 2

  • CPU RAM 有限(无法容纳所有模型权重)
  • 你正在优化云成本(RAM 较小的更廉价实例)
  • 你有许多模型需要管理(10 个以上)

什么情况下跳过睡眠模式

  • 你只使用单模型(无需切换)
  • 模型切换极其罕见(每天/每周一次)
  • 两个模型都能同时装入 GPU 内存

总结

vLLM 睡眠模式将多模型 GPU 服务从 30-100 秒的重新加载惩罚缩减为亚秒级切换。基准测试结果足以说明问题。

  • 模型切换快 18-200 倍,具体取决于模型大小和硬件
  • 推理快 61-88%(预热模型 vs 冷启动)
  • 总时间节省 65-68%
  • 适用于各种规模:0.6B 到 235B 参数,无论小型还是大型 GPU

LLM 服务的未来在于多模型化,而睡眠模式使这一切在今天成为现实。

致谢

特别感谢 Vensen Mu, Jeff Aw, Jun Kang Chow, Tun Jian Tan, Pin Siang Tan, Amir Balwel, Ye Hur Cheong, Zhiyao CenKaichao You 开发了睡眠模式功能并撰写此博客。