将推理冷启动时间降低40倍:真正无服务器GPU背后的工程实现

在当今的 AI 时代,推理需求呈现出极端的波动性。不同于可预测且稳定的训练工作负载,推理受外部用户行为驱动,导致需求呈尖峰式波动。对于工程师而言,这在服务质量(QoS)与成本之间形成了矛盾:为应对峰值而过度配置 GPU 会导致糟糕的“GPU 分配利用率”,而配置不足则会引发延迟峰值和 503 错误。

要实现“真正无服务器”GPU,需要将从请求到运行副本的扩展时间从分钟缩短到秒级。Modal 实现了一套四项关键优化——云缓冲区、定制惰性文件系统(FUSE)、CPU 检查点/恢复以及 CUDA 检查点/恢复——将冷启动时间降低至最高 40 倍(约从 2,000 秒降至 50 秒)。

1. 将实例分配从热点路径中移除

扩展过程中的首个瓶颈是启动新虚拟机并进行健康检查所需的时间,可能需要数分钟。Modal 通过维护一组 云缓冲区——跨多个应用共享的空闲、健康的 GPU——将其从关键路径中移除。

通过将新副本调度到这些预热单元并异步补充缓冲区,系统消除了初始分配延迟。这一过程使用 Google 的 GLOP 求解器作为线性规划问题进行管理,以平衡成本、请求容量和观察到的云提供商供给。

关键是,这种方法包含了积极的 GPU 健康检查。由于 GPU 的故障率高于标准服务器硬件,Modal 实现了两层健康检查:启动时的短时主动检查,以及每周一次的更深入诊断(如 dcgmi diag)。

2. 通过 ImageFS 实现惰性容器加载

标准容器启动的瓶颈在于需要拉取并解压数 GB 的根文件系统数据。Modal 通过使用基于 libfuse 构建的自定义文件系统 ImageFS,将容器启动器与镜像交付解耦,从而解决了这一问题。

惰性加载与内容寻址

ImageFS 并不在启动时加载整个镜像,而是仅加载元数据(索引),耗时不足 100 ms。实际文件内容会在应用请求时惰性加载。由于大多数容器从未访问其文件系统的大部分内容(例如地区或时区数据),因此大量镜像实际上并未被传输。

为优化被访问的数据,Modal 使用了 分层、内容寻址缓存

  • 页面缓存(Page Cache): 对最频繁的访问提供微秒级延迟。
  • 本地 SSD: 为常用内容提供高吞吐量存储。
  • 区域 CDN/Blob 存储: 为数据的长尾提供无限容量。

通过使用内容寻址而非基于路径或层的缓存,Modal 确保不同镜像之间共享的字节仅存储一次,无论它们位于哪个层中。

3. 使用 CPU 快照快速启动主机

即使容器已启动,应用仍需进行初始化。在以 Python 为主的 AI 堆栈中,简单的 import torch 可能触发数千次系统调用并产生数秒的开销。

Modal 利用 检查点/恢复(Checkpoint/Restore,C/R) 绕过此过程。通过使用 gVisor 的 runsc 运行时,Modal 将容器视为状态机。他们对进程进行内存快照——包括堆、线程状态和文件描述符表——并将其保存到磁盘。

当需要新副本时,系统直接从该快照恢复进程到内存中。这会将应用“快进”至就绪状态,使主机侧启动时间约缩短 10 倍。但这要求快照与底层 CPU 指令集兼容(例如,避免使用特定 AWS 实例类型不支持的指令)。

4. 使用 CUDA 检查点消除设备初始化

最后且通常最关键的瓶颈是 GPU 端的初始化。它包括两个主要任务:

  1. 权重加载(Weight Loading): 将数十亿参数从存储移动到 GPU VRAM。
  2. 推理引擎设置(Inference Engine Setup): 计算密集型任务,如捕获 CUDA 图或运行 Torch 编译器。

权重加载主要是吞吐量瓶颈(受网络/磁盘速度限制),而引擎设置则是计算瓶颈。Modal 利用最新的 Nvidia 驱动功能,将 设备内存 检查点保存到主机内存中。

通过结合主机端和设备端的快照,Modal 能够恢复完整的 CUDA 上下文。对于 vLLM 或 SGLang 等大语言模型服务器,这显著降低了启动延迟。例如,在使用 1 GiB 模型的测试中,启用快照后 vLLM 的启动延迟从平均约 95 秒降至约 13 秒。

延迟降低汇总

优化 目标组件 延迟影响
Cloud Buffers 机器管理 分钟 $\rightarrow$ 秒
ImageFS (FUSE) 本地 SSD / 网络 分钟 $\rightarrow$ 秒
CPU Snapshots CPU / RAM 数十秒 $\rightarrow$ 秒
CUDA Snapshots GPU / VRAM 分钟 $\rightarrow$ 数十秒

实际案例:Reducto

这些优化使得峰值与平均值比率高的工作负载能够高效扩展。Reducto 是一个文档处理平台,使用视觉语言模型处理海量企业数据集。其工作负载需要在短时间内扩展至数千个 GPU,以满足紧迫的交付期限。通过使用 GPU 内存快照,Reducto 将冷启动时间从约 70 秒降低至约 12 秒,使其能够以真正无服务器的方式运行“千 GPU”工作负载,而无需维持昂贵的空闲容量。

技术反思与注意事项

虽然 Modal 的方案非常有效,但社区指出了若干技术权衡:

  • FUSE 开销: 使用 libfuse 会在用户空间和内核空间之间产生额外的上下文切换。虽然对吞吐量密集的 AI 工作负载影响可忽略,但对延迟敏感的文件操作可能成为瓶颈。
  • 快照脆弱性: 内存快照对宿主环境高度敏感。在具备特定 CPU 指令的机器上创建的快照,无法在缺少这些指令的机器上恢复,这需要为异构集群准备多份快照。
  • 多 GPU 复杂性: 对多 GPU 程序进行快照具有挑战性,因为像 nccl 这样的通信库并未为暂停设计,恢复过程中可能导致死锁。

Sources