vLLM 睡眠模式实现零重载模型切换
引言
多模型服务的难题: 您有两个大语言模型(LLM),每个都能单独放入您的 GPU,但无法同时容纳。传统解决方案迫使您做出糟糕的权衡:
- 保持两个模型都加载 → 需要 2 倍的 GPU 显存(昂贵,通常不可行)
- 按需重新加载模型 → 每次切换需要 30-100+ 秒(缓慢,浪费资源)

vLLM 睡眠模式提供了第三种方式: 模型可在数秒内休眠并快速唤醒——实现了按需加载的效率与持久化服务的速度。
两种睡眠级别满足不同需求
- 级别 1: 将权重卸载到 CPU 内存(唤醒时间快)
- 级别 2: 完全丢弃权重(唤醒时间几乎同样快,内存占用极小)
两种级别都比完全重载快 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 vs 无睡眠模式的性能
下面的交互式图表显示了执行 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 图 | ✅ 是 | ❌ 每次重新捕获 |
| 进程状态(Python、CUDA 上下文) | ✅ 是 | ❌ 每次重启 |
| GPU 内核 JIT 缓存 | ✅ 是(初次预热后) | ❌ 每次重新编译 |
关键区别
- 不使用睡眠模式: 进程在卸载时终止 → 您无法从预热中受益
- 必须重启 Python 进程和 CUDA 上下文
- 必须重新初始化内存分配器
- 必须重新捕获 CUDA 图
- 必须重新 JIT 编译内核(DeepGEMM、FlashInfer、TorchInductor)
- 结果: 首次推理速度慢 4-7 倍(参见基准测试:0.92 秒唤醒 vs 3.72 秒冷启动)
- 使用睡眠模式: 进程保持存活 → 预热效果显著
- ✅ 分配器、图、进程状态和 JIT 内核在初次预热后都得到保留
- 结果: 首次推理保持快速(约 1 秒),避免了 3-4 秒的冷启动惩罚
说明
时间因模型大小、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.8 秒),与冷启动相比实现了 58-203 倍的加速
- 总时间节省:62%(5 次模型切换,85 秒 vs 226 秒)
- 小型模型的近乎即时切换(0.1 秒唤醒时间),使多模型服务感觉无缝
- 证明了睡眠模式在不同 GPU 等级和模型大小上均有效
睡眠级别:选择正确的模式
vLLM 睡眠模式提供两种级别,各有不同的权衡
级别 1(默认): 将模型权重卸载到 CPU 内存,丢弃 KV 缓存
- 最快的唤醒时间(小模型约 0.1-0.8 秒,大模型约 3-6 秒)
- 需要足够的 CPU 内存来存储模型权重
- 最适合: CPU 内存充足、模型切换频繁的系统
级别 2: 丢弃模型权重和 KV 缓存,仅在 CPU 中保留缓冲区(如 rope 缩放张量等)
- 唤醒时间较慢(小模型约 0.8-2.6 秒),因为需要从磁盘重新加载权重
- CPU 内存占用极小 - 仅保留小型缓冲区
- 最适合: CPU 内存有限或需要管理许多无法全部放入内存的模型的系统
性能比较:级别 1 vs 级别 2 vs 无睡眠
GPU:A100 (TP=1) | vLLM 0.11.0 | 编译:
cudagraph_mode: FULL_AND_PIECEWISE比较所有三种模式:级别 1(最快)、级别 2(内存占用最小)、无睡眠。悬停查看确切时间。
性能总结
| 模式 | 总时间 | 唤醒时间 (A/B) | CPU 内存 | 最适合 |
|---|---|---|---|---|
| 无睡眠 | 357.1 秒 | N/A(完全重载) | 最小 | 单一模型,无需切换 |
| 级别 1 | 112.6 秒 | 0.26 秒 / 0.82 秒 | 高(每个模型约 GB) | 切换频繁,内存充足 |
| 级别 2 | 124.6 秒 | 0.85 秒 / 2.58 秒 | 最小(每个模型约 MB) | 内存有限,成本优化 |
关键见解
- 级别 1 最快(比无睡眠快 68%),但需要大量 CPU 内存
- 级别 2 几乎同样快(比无睡眠快 65%),且内存需求极小
- 级别 2 唤醒比级别 1 慢约 3 倍(Qwen3-0.6B 为 0.85 秒 vs 0.26 秒),因为需要重载权重
- 两种睡眠模式都比无睡眠模式有巨大改进
为什么级别 2 仍然比无睡眠模式快
乍一看,这似乎有悖常理:级别 2 从 SSD 重新加载权重(就像“无睡眠模式”一样),那么为什么它总体上快 23-45 倍?
答案:权重加载只是五个成本之一
当您在不使用睡眠模式的情况下重新加载模型时,您需要支付所有这些成本:
| 成本 | 级别 2 | 无睡眠模式 |
|---|---|---|
| 1. 权重加载 (SSD → VRAM) | ❌ 必须支付 | ❌ 必须支付 |
| 2. 进程初始化 | ✅ 跳过 | ❌ 必须支付 |
| 3. 内存分配器设置 | ✅ 跳过 | ❌ 必须支付 |
| 4. CUDA 图捕获 | ✅ 跳过 | ❌ 必须支付 |
| 5. GPU 内核 JIT 编译 | ✅ 保留(已编译) | ❌ 完全编译 + 预热 |
级别 2 策略
- 从 SSD 重载权重(与无睡眠模式相同)
- 其他一切都保留: 进程状态、分配器实例、CUDA 图和已编译的 JIT 内核都完好无损
- 无需重新编译: 内核在初次预热期间已编译并保持缓存
- 每次切换平均耗时:约 2.6 秒(见上文基准数据)
无睡眠模式的现实
- 从 SSD 重载权重(与级别 2 相同)
- 其他一切都重建: 进程重启 + 分配器初始化 + 图重新捕获
- JIT 内核: 完全编译 + 显式预热程序 (
kernel_warmup()+ 虚拟运行) - 每次切换平均耗时:约 48 秒(见上文基准数据)
基准数据证明了这一点: 对于 5 次模型切换
- 级别 2: 总计 124.6 秒(每次切换平均约 2.6 秒)
- 无睡眠: 总计 357.1 秒(每次切换平均约 48 秒)
尽管两者都从 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.1 秒 | 124.6 秒 | 快 65% |
| Qwen3-0.6B 切换时间 | 平均 37.6 秒 | 平均 0.85 秒 | 快 45 倍 |
| Phi-3-vision 切换时间 | 平均 58.1 秒 | 平均 2.58 秒 | 快 23 倍 |
| Qwen3-0.6B 推理 | 平均 3.67 秒 | 平均 0.53 秒 | 快 86% |
| Phi-3-vision 推理 | 平均 6.30 秒 | 平均 0.76 秒 | 快 88% |
| 与级别 1 相比的唤醒时间 | - | 慢 3-10 倍 | 用 CPU 内存换取速度 |
何时使用级别 2
- CPU 内存有限: 系统无法在 CPU 内存中容纳所有模型权重
- 成本优化: 使用 CPU 内存较少的更便宜的云实例
- 模型众多: 在多个模型间切换,且 CPU 内存是限制因素
- 仍然有显著增益: 即使需要重载权重,级别 2 仍比无睡眠模式快 23-45 倍
级别 1 vs 级别 2 比较
- 级别 1:约 0.1-0.8 秒唤醒时间,每个模型需要约 10-100GB+ CPU 内存
- 级别 2:约 0.8-2.6 秒唤醒时间,每个模型仅需约 MB 级 CPU 内存
- 两者都比完全重载(约 20-100 秒)快得多
消融研究
预热对睡眠模式的影响
跳过预热阶段会影响性能吗?预热会在初始加载期间预编译 CUDA 图,这可能需要几秒钟。让我们比较有预热和无预热的情况。
GPU:A100 (TP=1) | vLLM 0.11.0 | 睡眠级别:1 | 编译:
cudagraph_mode: FULL_AND_PIECEWISE比较有预热(预编译)vs 无预热(懒编译)。悬停查看确切时间。
主要发现
| 指标 | 有预热 | 无预热 | 差异 |
|---|---|---|---|
| 初始加载时间 | 108.7 秒(包括 8.4 秒预热) | 101.1 秒(无预热) | 初始节省 7.6 秒 |
| 首次推理 (A) | 0.45 秒 | 2.59 秒 | 无预热慢 5.8 倍 |
| 首次推理 (B) | 0.93 秒 | 6.61 秒 | 无预热慢 7.1 倍 |
| 后续推理 | 平均 0.43 秒 | 平均 0.41 秒 | 无差异 |
| 总时间(5 次切换) | 119.5 秒 | 119.0 秒 | 几乎相同 |
见解
- 预热一次编译内核,惠及所有唤醒周期: 通过初始预热,JIT 编译和 CUDA 图捕获在加载时发生一次,并在所有后续的休眠/唤醒周期中保留
- 无预热,每次唤醒都付出编译成本: 5-7 倍的减速发生在每次唤醒后的首次推理中,而不仅仅是一次
- 编译后的内核在休眠/唤醒中保留: 在初始加载期间预热(8.4 秒)后,所有后续唤醒的首次推理都很快(0.45 秒,0.93 秒),证明内核保持缓存
- 最小化预热即可: 单个 1-token 的推理足以触发完整的 JIT 编译和 CUDA 图捕获,使预热成本非常低
- 用初始加载时间换取一致的性能: 8.4 秒的预热成本支付一次,并在所有模型切换中分摊
- 建议:对于生产工作负载,始终使用预热,以期获得一致、快速的推理性能
量化对睡眠模式的影响
量化(FP8)会影响睡眠模式的性能吗?我们在 A100 GPU 上测试了有和没有 FP8 量化的相同工作负载。
GPU:A100 (TP=1) | vLLM 0.11.0 | 睡眠级别:1 | 编译:
cudagraph_mode: FULL_AND_PIECEWISE比较 BF16(基线)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.2 秒 | 113.6 秒 | -5%(稍慢) |
| Qwen3-0.6B 唤醒时间 | 平均 0.27 秒 | 平均 0.18 秒 | 快 33% |
| Phi-3-vision 唤醒时间 | 平均 0.90 秒 | 平均 0.78 秒 | 快 13% |
| Qwen3-0.6B 推理 | 平均 0.41 秒 | 平均 0.44 秒 | -7%(稍慢) |
| Phi-3-vision 推理 | 平均 0.81 秒 | 平均 0.57 秒 | 快 30% |
| 初始加载时间 | 90.5 秒 | 96.9 秒 | -7%(预热时间更长) |
见解
- FP8 的唤醒操作更快(快 13-33%),因为内存移动更少
- FP8 改善了较大模型的推理性能(Phi-3-vision 快 30%),但对微小模型差异不大
- 使用 FP8 的初始加载时间更长,因为预热期间有量化开销
- 初始加载后,FP8 提供更平滑的切换和更快的唤醒周期
- 对于切换频繁的工作负载,FP8 更快的唤醒时间可以抵消较长的初始加载时间
决策指南:使用哪个睡眠级别?
何时使用睡眠级别 1
- 您有足够的 CPU 内存来容纳所有模型权重
- 您需要尽可能快的唤醒时间(0.1-6 秒)
- 您非常频繁地切换模型(每隔几秒/几分钟)
- 推理延迟的一致性至关重要
何时使用睡眠级别 2
- CPU 内存有限(无法容纳所有模型权重)
- 您正在优化云成本(内存较少的更便宜的实例)
- 您需要管理许多模型(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 开发了睡眠模式功能并撰写了这篇博客文章。