Serverless GPU 冷启动排查:镜像、模型与存储
说明 Serverless GPU 冷启动的两段延迟来源,并给出镜像层、模型权重与挂载存储的定位方法、Modal 配置和 RunPod 存储检查清单。
Serverless GPU 冷启动先沿三条线排查:镜像层是否被意外重建、模型权重是否在容器启动时下载、挂载存储是否能跨停止或删除保留。按 Modal 的冷启动说明,冷启动延迟分为等待容器进入预热(warm)状态的排队和首次调用初始化;延长 scaledown_window 可降低后续冷启动概率,但空闲资源仍会计费,因此算力租赁不能只比较一次接口响应。下面按镜像、模型、存储和验证顺序执行。
排查前先分清排队和初始化
先用同一请求、同一数据集和同一参数做两次记录:一次在没有就绪容器时发出,一次在已有预热容器时发出。若能取得客户端时间戳,分别记下首个 token 与总耗时。只有首次明显变慢时,先查代码导入、@modal.enter 和权重读取;并发时才普遍变慢,则先查等待预热容器的时间。
Modal 所称冷启动发生在没有就绪容器可复用时;其 冷启动参数说明 说明,所有 enter 方法完成前不会向容器路由输入。min_containers 设置容器数量下限,使 Function 不缩到零;buffer_containers 则在 Function 活跃时预置额外容器。
镜像层:先排除连锁重建
Modal 的 镜像文档 说明,镜像按每个 Image 方法调用对应的层缓存;其中一层缓存失效,会导致后续层连锁重建。因此,应把经常变化的层放在后面,避免一个变动文件触发整条后续构建链。
定位缓存问题时,强制构建说明 给出的命令如下:
MODAL_FORCE_BUILD=1 modal run ...
force_build=True 可以强制重建指定的构建步骤;MODAL_IGNORE_CACHE=1 则从顶部重建,但不会破坏后续构建使用的镜像缓存。强制构建适合诊断,不宜作为日常部署流程;比较请求冷启动时,还应把镜像构建记录与首次请求记录分开。
模型加载:把下载与启动拆开
按 Modal 的生命周期文档,@modal.enter 会在新容器启动时调用,适合加载模型权重或导入镜像中特有的包;使用生命周期钩子需要采用 @app.cls 类语法。把工作移入启动钩子后,仍应单独记录其完成时间。
Modal 的 vLLM 官方示例 使用 Modal Volume 缓存 Hugging Face 权重,避免每次启动服务器时重新下载,并提供以下关键配置:
hf_cache_vol = modal.Volume.from_name("huggingface-cache", create_if_missing=True)
cmd += ["--enforce-eager" if FAST_BOOT else "--no-enforce-eager"]
FAST_BOOT=True 会使用 --enforce-eager,关闭 Torch 编译和 CUDA graph capture,以启动速度换取生成性能。官方示例建议经常从零扩容的服务使用 True,通常同时运行多个副本时使用 False。示例中的 scaledown_window=15 * MINUTES 和 startup_timeout=10 * MINUTES 只是该示例的设置,不能当作通用默认值。
存储:算力租赁中的重启与数据边界
按 RunPod 的网络卷文档,network volume 独立于 Pod,删除 Pod 后仍可保留数据。对于 Pod,它必须在创建时挂载且不能事后卸载,并替换 /workspace 下的默认 volume disk;在 Serverless worker 中,挂载路径是 /runpod-volume。把单个 network volume 挂到 Serverless endpoint,会把 worker 限定在该卷所在的数据中心,可能限制 GPU 可用性和故障转移选择。
同一 并发与计费说明 提醒,多个 worker 同时写入同一卷可能造成数据损坏;Pod 停止后存储费用仍会继续产生,余额不足以覆盖费用时,网络卷最终可能被终止,数据无法恢复。应用应自行协调并发写入,并把挂载成功与备份完成分开检查。
从自己的账单或报价填入实际数值:
NETWORK_VOLUME_CHARGE = YOUR_VALUE × YOUR_VALUE
TOTAL_CHARGE = NETWORK_VOLUME_CHARGE + YOUR_VALUE
前两个 YOUR_VALUE 分别代表可计费存储量和当前单价,最后一个只填写账单中实际存在的其他费用。
部署后怎样确认改动有效
按 Modal 的 vLLM 部署示例,部署命令为:
modal deploy vllm_inference.py
同一示例说明,Modal Server 没有活动容器时会用 503 Service Unavailable 拒绝请求。得到该状态时,先确认是否存在活动容器,不要直接归因于模型文件或接口参数。
部署后先重复前面的冷启动与预热状态对照,再用 vLLM 的 Benchmark CLI 文档 所列的 vllm bench serve 做功能评估和回归测试:
vllm bench serve \
--backend vllm \
--model NousResearch/Hermes-3-Llama-3.1-8B \
--endpoint /v1/completions \
--dataset-name sharegpt
--request-rate 默认是 inf,会立即发送全部请求;需要观察受控流量下的排队时,可按文档填入有限的 YOUR_VALUE。
同一 指标说明 要求关注 request throughput、output-token throughput 和 total-token throughput。TTFT 从客户端发出请求算到收到首个流式输出;ITL 是相邻流式输出之间的间隔;TPOT 按请求计算并不包含首个 token。对同一 server 重复执行测试可能命中 prefix cache 并抬高吞吐量,因此不能只比较两次原始结果。
常见出错点
- 不要在一次前后对比中同时调整镜像层、模型加载和预热容器,否则无法判断哪项改动生效。
- 不要把强制镜像重建当成常规启动步骤;构建波动与首次请求波动应分别记录。
- 不要把存储挂载成功视为备份完成;挂载路径、并发写入、生命周期和持续费用需要分别核对。
这些步骤均依据正文链接的官方文档整理,使用前请对照当前版本复核。