\n\n本文分析了 GPU 推理中长达 8 分钟的冷启动问题,揭示了节点配置、镜像拉取、权重下载和内核编译等六大瓶颈。通过优化配置及基础设施,针对不同模型规模实现了 80%-93% 的启动加速,将热节点重启时间缩短至 30 秒以内,显著降低了推理算力的闲置成本。
译自:Cut GPU inference cold start from 8 minutes to less than a minute
作者:Sajjan Gundapuneedi
我们对从 pod 创建到 GPU 节点首次推理响应的完整路径进行了监测,该节点运行着一个 70B 参数级别的模型。八分钟。六个连续阶段。我们本以为只有一个瓶颈,结果却发现了六个,且哪个瓶颈占主导地位取决于模型的大小。
对于 64 GB 的模型,65% 的启动时间花费在重新编译 CUDA 内核上,而这些内核每次产生的结果都是相同的。对于 203 GB 的模型,92% 的时间花费在从 S3 下载权重上,其调用模式导致 98% 的可用带宽处于闲置状态。这两个问题都可以通过配置更改来修复,但默认情况下都没有修复。
“八分钟。六个连续阶段。我们本以为只有一个瓶颈。结果却发现了六个。”
我们将首次服务 token 时间 (TTFTS) 定义为从 pod 创建到 GPU 输出第一个推理响应的时钟时长。这并非首次 token 时间 (TTFT),后者衡量的是模型预热后每个请求的延迟。TTFTS 是一次性的启动成本。TTFT 在 TTFTS 结束后开始。
以下是我们取得的成果:
| 场景 | 描述 | 优化前 | 优化后 | 缩减比例 |
| 热节点上的 Pod 重启 | 现有节点上的权重加载 + 编译 | 1.5-8 分钟 | 30 秒以内 | 80-93% |
| 从零开始的新节点 | 全新预配节点,无缓存 | 8-15 分钟 | ~5 分钟 | 40-65% |
热节点行是你每次 pod 重启时所付出的代价:扩容事件、滚动更新、OOM 恢复。这就是 80-93% 的效率提升,且仅需更改配置即可实现。冷节点行包括约 2 分钟的固定基础设施成本(节点预配和框架初始化),这是任何应用层优化都无法消除的。其余的是可以通过平台和配置修复来消除的可避免浪费。热节点优化涉及环境变量和卷挂载,适用于任何 Kubernetes 集群。冷节点优化需要 EKS Auto Mode,它预装了预编译的 NVIDIA 驱动、SOCI (Seekable OCI) 并行镜像拉取和 NVMe 实例存储挂载。
所有模型启动测量均在运行 Amazon EKS Auto Mode 的 p5.48xlarge 实例上进行,S3 流量直接路由(绕过 NAT 网关),容器镜像位于私有 Amazon ECR 存储库中(与计算区域相同)。模型启动改进比例 (80-93%) 在不同实例类型间保持一致(已在 P 系列和 G 系列上验证)。冷节点时间随网络带宽和 CPU 核心数而变化。有关权重加载和编译缓存配置,请参阅 Accelerate model loading on Amazon EKS。
Kubernetes 生态系统在 2026 年的推理堆栈方面取得了实质性进展。OCI 镜像卷现在已可稳定用于模型交付。动态资源分配 (DRA) 为 GPU 提供了结构化属性,而不是不透明的整数计数,并为将 GPU 分配给工作负载提供了灵活性。Gateway API 拥有支持推理的路由扩展。但这些原语都无法解决完整的冷启动堆栈:即“pod pending”到“首次服务 token”之间的六个层级,每一层都有其自身的瓶颈和修复方法。
冷启动的六个层级
当一个新的推理 pod 在刚预配的 GPU 节点上启动时,它在服务第一个请求前会经过六个不同的阶段:
- 节点预配。 Karpenter 启动 EC2 实例,引导它并将其注册到 Kubernetes API 服务器(约 60-90 秒)。
- GPU 驱动初始化。 驱动内核模块必须加载并暴露加速器设备。
- 容器镜像拉取。 推理引擎镜像(压缩后 8-12 GB)必须传输到节点并解压。
- 模型权重下载。 模型文件必须从对象存储流式传输到 GPU 内存中。
- GPU 内核编译。 torch.compile 追踪模型图并生成优化的 CUDA 内核。
- 引擎初始化。 CUDA 图捕获、KV 缓存分析和 HTTP 服务器启动(30-120 秒,取决于编译是否已缓存)。
每一层都有不同的瓶颈、不同的修复方法和不同的负责人。
哪一层占主导取决于模型大小
在深入研究每一层之前,有一个发现影响了我们所有的决策:瓶颈不是固定的。
我们监测了模型启动路径(第 4 层和第 5 层),并针对两种模型规模分别测量了每个阶段:
64 GB 模型 (Qwen3.6-35B-A3B):
- 权重加载:~29 秒(占模型启动的 35%)
- torch.compile:~53 秒(占模型启动的 65%)
203 GB 模型 (Llama-4-Scout, TP=4,其中 TP 是张量并行,将模型拆分到多个 GPU 上):
- 权重加载:~423 秒(占模型启动的 92%)
- torch.compile:~34 秒(占模型启动的 8%)
对于小于约 100 GB 的模型,编译占主导地位。对于更大的模型,网络传输占主导地位。torch.compile 的时间大致保持不变(它取决于图的复杂性,而不是参数数量)。权重加载随文件大小线性扩展。
“对于小于约 100 GB 的模型,编译占主导地位。对于更大的模型,网络传输占主导地位。”
这意味着任何单层优化都有其上限。
第 1 层:节点预配
在 EKS Auto Mode 和 Karpenter 管理的集群上,加速实例的节点预配从 pod pending 到节点 Ready 大约需要 60-90 秒。Karpenter 直接调用 EC2 Fleet API,并在几秒钟内对挂起的 pod 做出响应,将预配保持在 EC2 启动的最低限度。
第 2 层:GPU 驱动初始化
NVIDIA GPU Operator 在默认配置下,由于需要从源码编译驱动内核模块,会给节点启动增加 2-3 分钟。这个成本在每个新节点上都会重复出现。
当平台控制整个堆栈(操作系统镜像、内核版本、驱动版本、引导顺序)时,可以在镜像构建时预编译驱动内核模块。节点启动后,运行 modprobe 加载已编译的 .ko 文件,GPU 只需几秒钟即可就绪。
这一点现在比以前更重要。Blackwell 架构的 GPU(G7、G7e 实例)必须独占使用 NVIDIA 的开源内核模块。旧的 Maxwell/Pascal/Volta GPU 只能运行专有模块。一个同时拥有旧版和下一代 GPU 节点的集群需要不同的驱动、不同的 AMI 和不同的升级周期。一个按实例系列预编译正确模块的托管平台消除了这种复杂性。
在 EKS Auto Mode 上,GPU 驱动可在几秒钟内加载(在镜像构建时预编译),而运行时编译方法则需要 2-3 分钟。
第 3 层:容器镜像拉取
生产环境中的 vLLM 或 SGLang 推理镜像通常压缩后为 8-12 GB。标准的 containerd 顺序拉取层,逐个在内存中解压,并写入磁盘。在这种大小下,根据实例类型和可用的 CPU 核心数,顺序拉取在冷节点上需要 2-4 分钟。对于更大的自定义镜像(压缩后 30-50 GB),containerd 在解压过程中可能会完全耗尽内存。
EKS Auto Mode 使用 SOCI 的并行拉取模式,它取代了 containerd 的默认 snapshotter。SOCI snapshotter 通过 HTTP 范围请求并发下载层块,并将每个块直接写入磁盘的目标字节位置(没有内存顺序缓冲区)。解压在所有可用 CPU 核心上并行运行。
拉取时间受到 CPU 限制的解压速度的瓶颈影响,而非网络带宽。我们直接证实了这一点:一个拥有 400 Gbps 网络的 p4d.24xlarge 仅达到了约 1 Gbps 的有效拉取吞吐量,因为 CPU 解压是制约因素。在拥有更多核心(48+ vCPU)的实例上,SOCI 并行拉取将镜像拉取时间从 2-4 分钟缩短至 30-60 秒。在核心较少的较小实例上,改进效果不大,因为解压无法有效地并行化。有关受限内存并行拉取如何处理超过 30 GB 的镜像而不出现 OOM 的更深入研究,请参阅 Bounded-Memory Parallel Image Pulling for Large Container Images。
第 4 层:模型权重下载
权重加载最明显的优化方案是:增加并行连接。将模型文件分割成小块,并发下载,填满网络管道。
我们在 p5.48xlarge 上测试了从同区域 S3 流式传输 64 GB 模型的情况。结果是反直觉的:
| 块大小 | 所需连接数 | 权重加载时间 |
| 256 MB | 256 | 13.98 秒 |
| 512 MB | 128 | 14.20 秒 |
| 2 GB | 34 | 13.62 秒 |
| 4 GB | 17 | 13.35 秒 |
| 8 GB | 9 | 21.80 秒 (+56%) |
256 个并行连接并没有比 17 个带来任何好处。唯一的失败模式是 8 GB 的块(超过了分片文件大小),导致了 56% 的性能回退。
为什么?因为开源的 Run:ai Model Streamer(已集成到 vLLM 和 SGLang 中)在每个工作线程内顺序处理 S3 范围请求。分配给 3.9 GB 分片文件的工作线程在单个连接上依次下载其字节范围请求。并行性来自于在不同的文件上运行多个工作线程,而不是将一个文件拆分成更多片段。
我们最终选择了与典型的 SafeTensors 分片大小(每个文件 3-5 GB)匹配的 4 GB 块,并为缓慢的请求设置了积极的超时和重试机制。S3 GET 延迟具有可测量的长尾效应:在我们的测试中,很大一部分请求的时间比中位数长 2-3 倍,而一个卡住的连接会拖累整个模型的加载。我们没有等待,而是在速度低于阈值几秒钟后杀掉卡住的连接,并在新连接上重试。这遵循了 S3 自己的性能指导建议。
对于 203 GB 的模型,这些仅需配置的更改将权重加载时间从 423 秒缩短至 25 秒(94% 的改进)。对于 64 GB 的模型,从 29 秒缩短至 12 秒。无需修改代码,仅需环境变量。调整包括三个设置:与分片文件边界对齐的块大小(消除了串行子请求问题)、杀掉并重试卡住 S3 连接的最低速度阈值,以及与每个张量并行秩的分片文件数量相匹配的显式并发性。
第 5 层:GPU 内核编译
每次 vLLM 或 SGLang pod 启动时,PyTorch 都会追踪模型的计算图并将其编译为优化的 CUDA 内核。根据模型架构的不同,这需要 34-53 秒。对于相同的模型、GPU 类型和张量并行配置,其输出结果每次都是相同的。
而 Kubernetes 在每次 pod 重启时都会丢弃它。Pod 默认使用临时存储。当 pod 终止时,其本地文件系统会被销毁。下一个 pod 将从零开始重新编译。
“对于相同的模型、GPU 类型和张量并行配置,其输出结果每次都是相同的。而 Kubernetes 在每次 pod 重启时都会丢弃它。”
将 torch.compile 缓存目录指向本地 NVMe 实例存储。GPU 实例自带 NVMe,EKS Auto Mode 会自动挂载它。第一个 pod 编译并写入约 15-30 MB 的缓存内核。同一节点上的第二个 pod 在 4-6 秒内即可加载预编译的二进制文件。只需一个卷挂载和环境变量。
该缓存是安全的,因为编译出的工件是确定性的:相同的模型架构 + GPU 架构 + 张量并行度 + PyTorch 版本等于有效的缓存。镜像更新或硬件更改会精确触发一次重新编译。
torch.compile 的时间与硬件无关。同一个模型在 H100 或 A100 上运行,编译时间都在约 52 秒左右。缓存命中(4-6 秒)在不同 GPU 类型之间同样一致。这意味着该优化在任何实例类型上都能以相同方式工作。
第 6 层:引擎初始化
权重加载和内核编译完成后,推理引擎必须捕获 CUDA 执行图并分析 KV 缓存内存。有了缓存的编译内核,这一过程可在 30-45 秒内完成。如果没有缓存,图捕获会触发额外的 JIT 编译,需要 60-120 秒。
这就是为什么 torch.compile 缓存具有巨大影响的原因:它不仅加速了第 5 层,还加速了第 6 层。缓存的编译将 2-3 分钟的组合阶段缩短为 35-50 秒的组合阶段。
框架初始化(Python 解释器启动和 PyTorch 导入)增加了数十秒的固定开销,无法通过配置来减少。
复合效应
这六个层级是复合的。平台修复(第 1-3 层)消除了 4-8 分钟的开销:预编译驱动取代了 2-3 分钟的运行时编译,并行拉取将镜像传输时间从 2-4 分钟缩短至 30-60 秒,Karpenter 将节点预配保持在硬件最低限度。配置更改(第 4-5 层)将剩余的模型启动时间缩短了 80-93%。一旦编译缓存预热,引擎初始化(第 6 层)从 60-120 秒降至 30-45 秒。综合来看,冷节点 TTFTS 从 8-15 分钟降至约 5 分钟。
64 GB 模型 (Qwen3.6-35B-A3B), TP=2:
| 配置 | 第一个 pod | 后续 pod (热节点) |
| 基准 (无优化) | 82 秒 | 82 秒 |
| + S3 块调整 | 65 秒 | 65 秒 |
| + torch.compile 缓存 | 65 秒 | 16 秒 |
| 改进 | -21% | -80% |
203 GB 模型 (Llama-4-Scout), TP=4:
| 配置 | 第一个 pod | 后续 pod (热节点) |
| 基准 (无优化) | 457 秒 | 457 秒 |
| + S3 块调整 | 59 秒 | 59 秒 |
| + torch.compile 缓存 | 59 秒 | 32 秒 |
| 改进 | -87% | -93% |
后续热节点的 pod 数值对生产环境而言最为重要。这是你每次 pod 重启时付出的代价。80-93% 的缩减在不同实例类型间保持一致,因为优化针对的是软件瓶颈(调用模式、冗余编译),而不是硬件限制。
大规模冷启动的成本
为什么这很重要?因为 GPU 节点很昂贵,且推理流量具有突发性。
单个 p5.48xlarge 按需实例每小时成本为 55 美元。即使是推理中常用的 G 系列实例,每小时成本也为 10-20 美元。每一分钟的冷启动都是你在付费但未使用的 GPU 时间。如果你的自动缩扩容需要 8 分钟以上来增加容量,你就必须过度预配(在闲置 GPU 上浪费金钱)或在流量激增时承受延迟飙升。
“每一分钟的冷启动都是你在付费但未使用的 GPU 时间。”
当热节点上的模型启动时间缩短至 16-32 秒时,计算结果就变了。你可以更激进地进行缩放,保留更少的缓冲节点,并无需数分钟的启动延迟即可响应流量激增。
我们学到了什么
- 先分解,再优化。 对于 64 GB 的模型,torch.compile 占主导(65%)。对于 203 GB 的模型,S3 加载占主导(92%)。如果不分别测量每个阶段,我们就会优化错误的层级。
- 瓶颈随模型大小而翻转。 torch.compile 时间在模型大小间大致恒定。权重加载呈线性扩展。每个运行推理的团队都应该知道他们处于哪个阶段。
- “更多并行”需要理解执行模型。 每个线程内执行顺序工作的 256 个连接并不比 17 个连接更快。瓶颈在于调用模式,而非并发限制。
- 15-30 MB 可以节省 53 秒。 对较小模型最有影响的优化是持久化一个小小的缓存文件。在尝试加速之前,请始终检查昂贵的计算是否产生确定性的输出。
- 平台级控制实现了仅靠配置无法达到的优化。 预编译驱动、默认开启的并行镜像拉取和 NVMe 自动挂载是基础设施层的决策,它们向上复合。结合应用层的纯配置更改,这些变化将冷启动时间从分钟缩短至秒级。
- 生态系统正在构建正确的原语,但冷启动存在于它们之间。 OCI 镜像卷、DRA、推理感知路由和本地模型缓存都是真正的进步。但编译瓶颈和 S3 调优缺口位于任何上游 Kubernetes 原语都无法解决的空间中。有时,影响力最大的优化是一个卷挂载和两个环境变量,而不是一个新的 API。
有关完整的配置指南,包括环境变量、YAML 清单和特定于实例的建议,请参阅 Amazon EKS 用户指南中的 “Accelerate model loading on Amazon EKS”。全 工智能