AI 工作负载的扩容瓶颈,往往不是 Kubernetes 创建 Pod 的速度,而是 Pod 启动后漫长的初始化:下载数十 GB 模型权重、构建运行时、编译算子,再把模型载入 CPU 和 GPU 内存。为了扛住流量尖峰,团队通常只能提前保留昂贵的 GPU 实例。
GKE Pod snapshots 提供了另一条路径:把已经运行起来的 Pod 连同 CPU、GPU 内存状态保存下来,需要扩容时直接恢复,而不是从头启动。根据公开的基准结果,这种方式可将大型模型的启动延迟最多降低 89%,70B 参数模型可在约 37 秒内加载,8B 参数模型约为 15 秒。
冷启动为什么会成为扩容上限
传统推理服务增加一个副本时,每个新 Pod 都要重复一遍初始化流程:
- Kubernetes 调度 Pod,并分配 GPU。
- 容器拉取镜像、启动推理服务器。
- 下载或挂载模型权重。
- 将权重读入主机内存和 GPU 显存。
- 编译或预热推理内核。
- 健康检查通过,Pod 才开始接收流量。
对于数百 MB 的普通 Web 服务,这套流程通常可以接受;对于数十亿甚至数百亿参数的模型,权重加载可能占据大部分启动时间。即使节点和 GPU 已经就绪,新副本也无法立刻处理请求。
Pod 快照改变的是第 3 到第 5 步。平台先完整初始化一个 Pod,然后保存其运行状态,包括 CPU 和 GPU 内存,并将快照持久化到高吞吐 Cloud Storage。后续副本从这一状态恢复,跳过模型下载、显存加载和运行时预热。
这不是简单的容器镜像缓存。镜像缓存只减少镜像拉取时间,模型仍要重新加载;Pod 快照保存的是已经执行过初始化代码的运行状态,更接近“恢复进程”而不是“重新启动进程”。
两类最直接的使用场景
推理服务:让 GPU 跟随请求增长
对于 LLM 推理服务,可以在模型完成加载、健康检查即将通过时创建基准快照。扩容时,新副本恢复这份快照并快速进入 Ready 状态。
这种模式适合以下工作负载:
- 模型权重大,加载时间明显长于 Pod 调度时间;
- 流量存在明显峰谷,需要频繁扩缩容;
- GPU 单价高,长期保留空闲副本成本过高;
- 副本启动后的内存状态基本一致,适合从同一模板恢复。
Retake 的案例展示了这种模式的价值:其团队原本维护了一套编译产物缓存,将启动时间压缩到约 1 分钟,但仍要承担自定义缓存层的维护成本。切换到 Pod 快照后,启动延迟进一步降到约 8 秒,从而可以按任务动态启动和关闭 H100 GPU。
智能体沙箱:模板恢复与会话挂起
执行 LLM 生成代码或计算机操作时,通常需要为每个用户或工作流创建隔离沙箱。这里有两种快照策略:
- 模板快照:预装解释器、浏览器、依赖和工具,初始化完成后生成快照。新任务从统一模板恢复。
- 会话快照:用户暂时离开时挂起沙箱并保存完整状态,再次访问时恢复原有进程和内存。
前者解决“每个沙箱都要安装和预热”的问题,后者解决“为了保留会话而长期占用计算资源”的问题。对于不可信代码,快照并不会替代网络隔离、权限限制、seccomp、资源配额等安全措施;它只优化生命周期和启动速度。
可以这样实践:先测出真实启动延迟
在引入快照前,先建立冷启动基线。下面的脚本使用标准 kubectl 命令,把现有 Deployment 缩容到 0,再扩容到 1,并统计 Pod 达到 Ready 所需的端到端时间。
运行前请修改命名空间、Deployment 名称和标签选择器。该脚本可以直接保存为 measure-startup.sh 执行:
#!/usr/bin/env bash
set -euo pipefail
NAMESPACE="ai-inference"
DEPLOYMENT="llm-server"
SELECTOR="app=llm-server"
TIMEOUT="20m"
echo "Scaling ${DEPLOYMENT} to zero..."
kubectl -n "$NAMESPACE" scale deployment "$DEPLOYMENT" --replicas=0
kubectl -n "$NAMESPACE" wait \
--for=delete pod \
-l "$SELECTOR" \
--timeout="$TIMEOUT" || true
started_ms=$(date +%s%3N)
echo "Scaling ${DEPLOYMENT} to one replica..."
kubectl -n "$NAMESPACE" scale deployment "$DEPLOYMENT" --replicas=1
kubectl -n "$NAMESPACE" rollout status \
deployment/"$DEPLOYMENT" \
--timeout="$TIMEOUT"
ready_ms=$(date +%s%3N)
elapsed_ms=$((ready_ms - started_ms))
printf 'Time to Ready: %d ms (%d s)\n' \
"$elapsed_ms" "$((elapsed_ms / 1000))"
kubectl -n "$NAMESPACE" get pods \
-l "$SELECTOR" \
-o wide
建议分别运行以下测试,并记录 P50、P95,而不是只看一次结果:
- 节点、镜像和模型都没有缓存的完整冷启动;
- 节点已存在、容器镜像已缓存时的启动;
- 从 Pod 快照恢复时的启动;
- 多个副本同时恢复时的启动。
GKE Pod snapshots 通过声明式 CRD 配置快照策略。策略可以选择目标 Pod、存储位置和保留期限,也可以配置在工作负载发出信号后创建快照,或在 Pod 生命周期中按需触发。恢复时既可选择最近一次快照,也可指定明确的快照版本。
由于具体 CRD 的 API 版本和字段会随功能版本变化,不应直接猜测资源结构。实际落地时,可以围绕下面这份配置清单对照当前集群文档创建策略:
# 这是策略设计清单,不是可直接提交的 GKE CRD。
# 请将这些项目映射到当前版本 Pod snapshot CRD 的真实字段。
target:
namespace: ai-inference
podSelector:
matchLabels:
app: llm-server
snapshot:
trigger: workload-ready-signal
storage: cloud-storage
retention: 24h
restore:
mode: latest-successful
fallback: cold-start
关键点是不要在“容器刚启动”时创建快照,而要等到模型权重已经进入 GPU 显存、必要的编译和预热完成,并且应用状态处于可安全复制的边界。
快照不是免费的:需要控制一致性与存储成本
保存数十 GB 甚至更大的 CPU、GPU 内存状态会产生存储容量和读写流量。快照过于频繁,可能用存储成本换掉了 GPU 空闲成本;快照保留过久,则容易积累不可用的旧版本。
上线前应明确以下边界:
- 版本一致性:模型权重、容器镜像、GPU 驱动和运行时发生变化后,应重新生成快照。
- 外部连接:恢复后的数据库连接、网络套接字和临时凭据可能已经失效,应用应具备重连和刷新能力。
- 数据安全:内存快照可能包含令牌、用户数据或模型上下文,需要限制访问、设置保留期并审查加密策略。
- 容量峰值:大量副本同时恢复仍会竞争存储吞吐、网络带宽和 GPU 资源,应进行并发恢复压测。
- 降级路径:快照丢失、过期或恢复失败时,服务应能回退到普通冷启动。
落地顺序:先优化昂贵的初始化阶段
Pod 快照并不只适用于 AI。复杂 Java 单体应用、游戏服务器和初始化时间很长的遗留系统,同样可以受益。但判断是否值得采用,可以先看一个简单指标:初始化时间是否显著高于调度和容器启动时间。
推荐按以下顺序推进:
- 测量从扩容指令到业务 Ready 的真实延迟,并拆分调度、镜像、模型加载和预热耗时。
- 选择一个副本状态一致、外部依赖较少的推理服务进行试点。
- 在模型完全加载后创建快照,并验证恢复后的首个请求是否正确。
- 对比冷启动和快照恢复的 P50、P95、错误率及 GPU 空闲成本。
- 配置保留期、访问控制、版本标记和冷启动回退机制。
- 最后再调整 HPA、事件驱动扩缩容或队列阈值,避免恢复速度提高后仍沿用过度保守的容量策略。
它带来的核心变化并不是“让 Kubernetes 更快创建 Pod”,而是把扩容模型从重复初始化改成恢复已完成的计算状态。当模型加载本身就是主要成本时,这种从 restarting 到 resuming 的转变,才可能真正减少空闲 GPU,并让基础设施按需求增长。