GLM-5.3-NVFP4 部署实战系列[八]启动加速:编译缓存挂载与 CUDA 图捕获裁剪,首启 8 分钟 → 3 分钟

08 启动加速:编译缓存挂载与 CUDA 图捕获裁剪,首启 8 分钟 → 3 分钟

文章目录

  • [08 启动加速:编译缓存挂载与 CUDA 图捕获裁剪,首启 8 分钟 → 3 分钟](#08 启动加速:编译缓存挂载与 CUDA 图捕获裁剪,首启 8 分钟 → 3 分钟)

    • [1. 编译缓存挂载:一行挂载,六分钟到手](#1. 编译缓存挂载:一行挂载,六分钟到手)
    • [2. CUDA 图捕获裁剪:389 秒 → 约 1 分钟](#2. CUDA 图捕获裁剪:389 秒 → 约 1 分钟)
      • [2.1 先分清两种图模式:FULL 与 piecewise](#2.1 先分清两种图模式:FULL 与 piecewise)
      • [2.2 CUDA 图无法落盘缓存的原因](#2.2 CUDA 图无法落盘缓存的原因)
      • [2.3 默认值有多浪费和裁剪优化](#2.3 默认值有多浪费和裁剪优化)
    • [3. 两条启动加速原则的适用边界](#3. 两条启动加速原则的适用边界)
  • 模型部署调通之后,启动耗时就成了日常运维的痛点,尤其在你需要频繁重启调试、或在多机复刻部署时。

  • 本文记录我们如何把"页缓存热"的启动从 ~8 分钟压到 ~3 分钟:一靠把 torch.compile 的编译缓存挂载到宿主机,二靠裁剪 CUDA 图的捕获尺寸列表。

先看启动耗时的构成(页缓存热,87 分片加载仅 ~9s):

阶段 首启(无缓存) 缓存命中后
Dynamo 字节码转换 31.5s 1.8s
inductor 编译 ~6min 跳过
piecewise CUDA 图捕获 ~1min ~1min(见下文,无法缓存)
init engine 全程 ~8min ~3min

1. 编译缓存挂载:一行挂载,六分钟到手

  • vLLM 的 torch.compile 缓存默认写在容器内 /root/.cache/vllm。容器重建即丢,下次启动重新编译 ~6 分钟。解法是把宿主机目录挂进去(deploy.sh 已内置):
bash 复制代码
mkdir -p .compile_cache
docker run ... -v $PWD/.compile_cache:/root/.cache/vllm ...
  • 效果:Dynamo 字节码转换 31.5s → 1.8s,inductor 编译整体跳过 ,init engine 从 ~8min 降到 ~3min。缓存挂载后实测约 2.3G,内含三部分:
bash 复制代码
.compile_cache/
├── torch_compile_cache/    # inductor 产物(TRITON 缓存 + 编译 artifact)
├── modelinfos/             # 模型/配置哈希信息(缓存有效性判断依据)
└── dummy_cache/
  • 如何确认缓存命中 :看启动日志里 Dynamo 转换的耗时------命中时是 1.8s 量级,未命中是 31.5s 量级,后接 inductor 编译长日志。这是最直接的判据,比翻缓存目录可靠。

两个细节:

  1. 缓存挂载要放在 docker run 而不是 docker commit 里解决,缓存属于"运行时状态",镜像应该保持无状态,这样多机部署时只需要同步一个目录;
  2. 失效是自动且精确的 :vLLM 按代码与配置的哈希管理缓存,改了补丁文件(改变编译产物)或换了编译配置,对应产物自动失效重编,不需要手动清理;只改 MAX_NUM_SEQS 这类调度参数则不影响编译缓存。

2. CUDA 图捕获裁剪:389 秒 → 约 1 分钟

  • 剩下的 ~1min 是 CUDA 图捕获。这一步无法靠缓存解决

2.1 先分清两种图模式:FULL 与 piecewise

  • 排查编译崩溃期间我们用过 mode=none + cudagraph_mode=FULL,最终配置是默认编译 + piecewise 图。两者值得辨析:

  • FULL(整图):把整个 forward(含注意力、MoE)作为一张图捕获。不依赖 torch.compile,所以是编译崩溃期的天然避风港,把单流从 7.5 拉到 33 tok/s。

  • piecewise(分段,编译开启时的默认) :torch.compile 先把 forward 编译并切分,只在适合捕获的段(如 attention 之外的稳定段)上建图。它带来两个好处:图更精简、与编译优化叠加(最终 75.6 tok/s 里 CUDA 图与编译的贡献就是靠它同时拿到的)。

结论:FULL 是"保命用"的图,piecewise 是"得分用"的图。如果部署顺利,直接用默认 piecewise;只有编译路径有问题需要临时绕过时才退到 FULL。

2.2 CUDA 图无法落盘缓存的原因

  • CUDA Graph 记录的是本进程内的显存地址------kernel 参数里写死的是捕获那一刻的指针。进程重启后地址布局变了,落盘的图就是一堆悬空指针。所以 vLLM 每次启动都要现场重新捕获,这份时间账躲不掉,只能少捕几张。

2.3 默认值有多浪费和裁剪优化

  • vLLM 默认对一系列 batch size 逐个捕获,最多到 256 ------共 27 张图,实测捕获 389 秒 。而部署 --max-num-seqs 16:调度器根本不会排出超过 16 的 batch,batch 32/64/.../256 的图一张都不会被执行。把捕获列表限制在调度器实际会运行的尺寸以内即可:
bash 复制代码
--compilation-config '{"cudagraph_capture_sizes":[1,2,4,8,12,16]}'
  • 捕获耗时 389s → 约 1min ,图自身的显存占用约 1.17GiB (单张图也不小,少捕 20 张省的是真金白银的显存),日志证据:Graph capturing finished in 12 secs, took 1.17 GiB

  • 裁剪的依据只有一条:捕获尺寸上界 = MAX_NUM_SEQS。如果你把并发调大(如 32、64),捕获列表要跟着改,否则高并发段会退回 eager 执行,吞吐掉档。给不同部署规模的参考起点:

MAX_NUM_SEQS 建议 CUDAGRAPH_CAPTURE_SIZES
16(我们的场景) 1,2,4,8,12,16
32 1,2,4,8,16,24,32
64 1,2,4,8,16,32,48,64

两点说明:低尺寸段要密(批量小的请求最常见,decode 大部分时间落在 1--8 的图上);高尺寸段可以稀(走到那里的 batch 少,每多捕一张是线性增加的启动时间)。空值恢复默认CUDAGRAPH_CAPTURE_SIZES 留空时 vLLM 会捕到 256,如果业务真的会有 100+ 并发,那 389s 的捕获成本就得认。

3. 两条启动加速原则的适用边界

手段 适用 不适用
编译缓存挂载 所有开启 torch.compile 的 vLLM 部署;重启频繁的调试场景 补丁/模型变更后自动失效;换编译配置会重编
CUDA 图捕获裁剪 max_num_seqs 明确小于默认 256 的所有部署 需要支撑突发高并发的场景(列表上界要覆盖真实并发)
  • 合起来,最终配置下的启动时间线(页缓存热):
bash 复制代码
87 分片加载 ~9s → Dynamo 转换 1.8s → (inductor 跳过) → 图捕获 ~1min → 就绪
init engine 全程 ~3min;完整冷启动(含权重加载)约 5 分钟

下一篇:09 最终性能实测:并发、TTFT 与持续吞吐

相关推荐
一颗小树x6 小时前
vLLM大模型推理:Jetson AGX Thor 的 GPU 共享内存清理实战
jetson·vllm·vlm·gpu内存清理
论文复现现场1 天前
Qwen3.8-27B 做 GRPO 需要几张 GPU?4×RTX 4090 与 8×RTX 4090 显存、vLLM 和 ZeRO-3 配置分析
deepspeed·qlora·大模型训练·vllm·rtx4090·grpo·qwen3.8
安易算力1 天前
昇腾生态开发深度实践:CANN算子库架构解析与MindSpore模型优化
网络·容器·架构·kubernetes·vllm
SunnyRivers1 天前
vLLM 官方调优方案
优化·vllm
政企项目老覃2 天前
边缘 AI 推理部署:安防零售场景下的模型裁剪与端侧落地实践
人工智能·程序人生·算法·性能优化·vllm
赋创小助手2 天前
Qwen3.8-27B 本地推理 Benchmark 解析:llama.cpp、vLLM、SGLang 与长 Context 的性能差异
服务器·人工智能·大模型·qwen·vllm·sglang·context长度
论文复现现场2 天前
Llama/Qwen 70B 部署需要几张 RTX 4090?2卡、4卡、8卡显存、量化与 vLLM 选型
llama·qwen·vllm·大模型推理·大模型部署·rtx4090
鬓戈5 天前
Qwen3.8-27B + vLLM 性能优化
人工智能·性能优化·vllm