使用 vLLM 睡眠模式实现模型零重载切换
引言
多模型推理服务难题: 你有两个 LLM,每个都能装进 GPU,但无法同时装入。传统的解决方案被迫在两个糟糕的选择中权衡:
- 保持两个模型同时加载 → 需要 2 倍的 GPU 显存(昂贵,且通常不可行)
- 按需重新加载模型 → 每次切换需要 30-100+ 秒(缓慢,且浪费资源)

vLLM 睡眠模式提供了第三种选择: 模型在几秒钟内进入休眠并能快速唤醒——既拥有按需加载的高效率,又具备持久服务的响应速度。
两种睡眠级别满足不同需求
- 级别 1 (Level 1): 将权重卸载到 CPU RAM(唤醒速度极快)
- 级别 2 (Level 2): 完全丢弃权重(唤醒速度几乎同样快,CPU 内存占用极低)
两种级别都比完整重载快 18-200 倍,并能与张量并行 (TP)、流水线并行 (PP) 和专家并行 (EP) 无缝协作。
为什么睡眠模式优于快速权重加载器
即使拥有即时的权重加载能力,每次冷启动都会产生一些睡眠模式可以避免的隐藏成本:
| 成本项 | 描述 | 快速权重加载器 | 睡眠模式 |
|---|---|---|---|
| 1. VRAM 加载时间 | 将权重复制到 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_weights 和 reset_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 重启和重载。
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 图 (CUDA graphs) | ✅ 是 | ❌ 每次都要重新捕获 |
| 进程状态 (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 倍。
误差线显示了多次运行中的最小/最大变化。数值显示在柱状图上。
GPU: A100 | vLLM 0.11.0 | 睡眠级别: 1 | 编译设置:
cudagraph_mode: FULL_AND_PIECEWISE硬件可扩展性:A4000 GPU 结果
睡眠模式的好处不限于高端 GPU。以下是在 A4000 GPU 上运行较小模型的工作负载,证明了性能提升可以跨越不同的硬件层级和模型规模。
GPU: A4000 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译设置:
cudagraph_mode: FULL_AND_PIECEWISEA4000:推理性能
推理时间 = Prefill + Decode(唤醒/加载后的第一条请求)。 每个请求使用不同的问题以避免缓存影响,输出限制为 100 个 token。
误差线显示了多次运行中的最小/最大变化。数值显示在柱状图上。
GPU: A4000 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译设置:
cudagraph_mode: FULL_AND_PIECEWISEA4000:模型切换性能
误差线显示了多次运行中的最小/最大变化。数值显示在柱状图上。
GPU: A4000 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译设置:
cudagraph_mode: FULL_AND_PIECEWISEA4000 上的关键观察
- 推理性能: 唤醒模式使 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 scaling tensors 等)
- 唤醒时间较慢(小模型约 0.8-2.6s),因为需要从磁盘重新加载权重
- CPU RAM 占用极低 —— 仅保留极小的缓冲区
- 最适用于: CPU RAM 有限,或管理许多无法全部装入内存的模型时
性能对比:级别 1 vs 级别 2 vs 无睡眠
GPU: A100 (TP=1) | vLLM 0.11.0 | 编译设置:
cudagraph_mode: FULL_AND_PIECEWISE对比三种模式:级别 1(最快)、级别 2(最低 RAM)、无睡眠。悬停可查看精确耗时。
性能总结
| 模式 | 总时间 | 唤醒时间 (A/B) | CPU RAM 需求 | 最适合场景 |
|---|---|---|---|---|
| 无睡眠 | 357.1s | 不适用(完整重载) | 极低 | 单一模型,无需切换 |
| 级别 1 | 112.6s | 0.26s / 0.82s | 高(每个模型数 GB) | 频繁切换,RAM 充足 |
| 级别 2 | 124.6s | 0.85s / 2.58s | 极低(每个模型数 MB) | RAM 有限,成本优化 |
关键见解
- 级别 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:推理性能
推理时间 = Prefill + Decode(唤醒/加载后的第一条请求)。 每个请求使用不同的问题以避免缓存影响,输出限制为 100 个 token。
误差线显示了多次运行中的最小/最大变化。数值显示在柱状图上。
GPU: A100 (TP=1) | vLLM 0.11.0 | 睡眠级别: 2 | 编译设置:
cudagraph_mode: FULL_AND_PIECEWISE级别 2:模型切换性能
误差线显示了多次运行中的最小/最大变化。数值显示在柱状图上。
GPU: A100 (TP=1) | vLLM 0.11.0 | 睡眠级别: 2 | 编译设置:
cudagraph_mode: FULL_AND_PIECEWISE关键观察
| 指标 | 无睡眠 | 级别 2 | 改进项 |
|---|---|---|---|
| 总时间 (5 次切换) | 357.1s | 124.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 更少的云实例
- 管理大量模型: 在多个模型之间切换,CPU 内存成为瓶颈
- 依然有显著提升: 即使有权重重载,级别 2 仍比无睡眠模式快 23-45 倍
级别 1 vs 级别 2 对比
- 级别 1:约 0.1-0.8s 唤醒时间,每个模型需要约 10-100GB+ 的 CPU RAM
- 级别 2:约 0.8-2.6s 唤醒时间,每个模型仅需要约数 MB 的 CPU RAM
- 两者都显著快于完整重载(约 20-100s)
消融研究
预热 (Warm-Up) 对睡眠模式的影响
跳过预热阶段会影响性能吗?预热会在初始加载期间预编译 CUDA 图,这可能需要几秒钟。让我们对比一下有无预热的情况。
GPU: A100 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译设置:
cudagraph_mode: FULL_AND_PIECEWISE有预热(预编译)vs 无预热(延迟编译)的对比。悬停查看精确耗时。
关键发现
| 指标 | 有预热 | 无预热 | 差异 |
|---|---|---|---|
| 初始加载时间 | 108.7s (含 8.4s 预热) | 101.1s (无预热) | 初始节省 7.6s |
| 首次推理 (A) | 0.45s | 2.59s | 无预热时慢 5.8 倍 |
| 首次推理 (B) | 0.93s | 6.61s | 无预热时慢 7.1 倍 |
| 后续推理 | 平均 0.43s | 平均 0.41s | 无差异 |
| 总时间 (5 次切换) | 119.5s | 119.0s | 几乎相同 |
见解
- 预热编译一次,惠及所有唤醒周期: 有了初始预热,JIT 编译和 CUDA 图捕获在加载时发生一次,并在后续所有休眠/唤醒周期中保留。
- 无预热,每次唤醒都要付编译费: 5-7 倍的减速发生在每一次唤醒后的首次推理,而不止是一次。
- 已编译算子跨休眠/唤醒保留: 在初始加载(8.4s)预热后,所有后续唤醒的首次推理都很快(0.45s, 0.93s),证明算子保持在缓存中。
- 极简预热即可: 单个 1-token 的推理就足以触发完整的 JIT 编译和 CUDA 图捕获,使预热成本非常低。
- 牺牲初始加载时间换取一致的性能: 8.4s 的预热成本支付一次,平摊到所有模型切换中。
- 建议:对于生产工作负载,始终使用预热,以确保一致且快速的推理。
量化对睡眠模式的影响
量化 (FP8) 会影响睡眠模式的性能吗?我们在 A100 GPU 上测试了开启和关闭 FP8 量化的相同工作负载。
GPU: A100 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译设置:
cudagraph_mode: FULL_AND_PIECEWISEBF16(基准)vs FP8 量化对比。悬停查看精确耗时。
消融:推理性能 (BF16 vs FP8)
推理时间 = Prefill + Decode(唤醒/加载后的第一条请求)。 每个请求使用不同的问题以避免缓存影响,输出限制为 100 个 token。
误差线显示了多次运行中的最小/最大变化。数值显示在柱状图上。
GPU: A100 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译设置:
cudagraph_mode: FULL_AND_PIECEWISE消融:模型切换 (BF16 vs FP8)
误差线显示了多次运行中的最小/最大变化。数值显示在柱状图上。
GPU: A100 (TP=1) | vLLM 0.11.0 | 睡眠级别: 1 | 编译设置:
cudagraph_mode: FULL_AND_PIECEWISE关键发现
| 指标 | BF16 | FP8 | 改进项 |
|---|---|---|---|
| 总时间 (5 次切换) | 108.2s | 113.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.5s | 96.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%
- 在完整工作负载中实现 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 Cen 和 Kaichao You 开发了睡眠模式功能并撰写本博文。