跳到主要内容

存储与模型加载

大模型部署里,存储通常不参与每个 token 的核心计算,但它会决定模型能不能快速启动、能不能稳定扩容、能不能在多副本服务中顺利分发。

可以先用一句话理解:

存储负责把模型权重可靠、快速、可重复地送到推理进程和 GPU 前面。

如果存储链路设计不好,GPU 可能很强,但服务仍然会出现冷启动慢、滚动发布拖很久、多个副本同时启动把网络盘打满、缓存目录膨胀、容器镜像过大等问题。

1. 存储在模型服务中的作用

模型服务中的存储不只是“放文件”的地方。它通常参与这些环节:

  • 下载模型权重、tokenizer、配置文件和量化文件。
  • 保存 Hugging Face、ModelScope、vLLM、SGLang 等框架的本地缓存。
  • 在服务启动时读取 checkpoint 或 safetensors 分片。
  • 给多副本服务分发同一份模型。
  • 支撑热更新、版本回滚和灰度发布。
  • 保存日志、trace、请求样本和评测输出。
  • 在训练或微调场景中保存 checkpoint、optimizer state 和数据集。

对于在线推理来说,存储最直接影响的是启动和发布阶段,而不是稳定运行后的每 token 解码速度。模型一旦加载到显存或内存中,普通请求通常不会反复读完整权重文件。

但这不代表存储不重要。生产环境里经常真正卡住的是这些问题:

  • 新实例拉起太慢,扩容跟不上流量。
  • 发布时大量副本同时下载模型,打满对象存储、网络盘或出口带宽。
  • 缓存目录被多个版本模型撑满,节点磁盘耗尽。
  • 网络盘抖动导致加载失败或启动时间不稳定。
  • 容器镜像过大,镜像分发慢于模型本身加载。

2. HDD、SATA SSD 和 NVMe SSD

不同存储介质的差异主要体现在顺序读取、随机读取、延迟和并发能力上。

类型特点适合场景不适合场景
HDD容量大、成本低、随机访问慢冷归档、离线备份、低频数据集在线模型启动、高并发加载
SATA SSD比 HDD 快,成本适中,带宽有限中小模型、本地开发、普通缓存盘多个大模型同时加载
NVMe SSD带宽高、延迟低、并发能力强生产推理、本地模型缓存、多副本节点成本敏感的大规模冷存储
网络盘便于共享和集中管理,性能依赖网络和服务端集群共享、统一模型仓库强冷启动 SLA、突发多副本同时加载
对象存储容量弹性好,适合版本管理和分发源模型制品源、归档、跨区域分发直接作为高频启动读盘路径

大模型权重通常是几十 GB 到数百 GB。加载时多为大文件顺序读取,但也会有多个分片并发读取、metadata 查询、tokenizer 小文件读取和框架缓存检查。

因此,生产节点上更常见的方案是:

对象存储 / 模型仓库
-> 节点本地 NVMe 缓存
-> 推理进程加载到系统内存
-> 拷贝或映射到 GPU 显存

本地 NVMe 的价值不只是“更快”,还包括减少对远端仓库的重复读取,让服务重启和滚动发布更稳定。

3. 模型权重体积怎么估算

模型文件大小主要由参数量和精度决定。粗略估算方式是:

权重大小 ≈ 参数量 × 每个参数占用字节数
精度字节/参数7B 约占用70B 约占用
FP32428 GB280 GB
FP16 / BF16214 GB140 GB
INT8 / FP817 GB70 GB
INT4 / 4-bit0.53.5 GB35 GB

实际磁盘占用还会包括:

  • config.jsongeneration_config.json 等配置文件。
  • tokenizer 文件,例如 tokenizer.jsontokenizer.modelvocab.json
  • safetensors 分片索引,例如 model.safetensors.index.json
  • 量化元数据、adapter 权重或 LoRA 权重。
  • 多版本缓存、临时下载文件和未清理的旧 revision。

需要注意,磁盘权重大小不等于显存占用。显存还要计算 KV Cache、runtime、workspace 和并发余量,见 显存模型占用显存估算

4. 模型加载链路

一次典型的模型启动可以拆成几步:

检查本地缓存
-> 下载缺失文件
-> 读取 config 和 tokenizer
-> 读取权重分片
-> 反序列化 / mmap
-> 按 device map 或并行策略放置权重
-> 初始化推理框架 runtime
-> 预热请求或 CUDA graph

每一步都可能成为瓶颈。

阶段常见瓶颈表现
下载外网带宽、对象存储限流、代理不稳定首次启动极慢或失败
缓存检查小文件多、网络盘 metadata 慢启动前长时间无 GPU 占用
权重读取磁盘带宽不足、多副本争抢读盘打满,CPU 和 GPU 等待
反序列化CPU、系统内存不足内存峰值高,甚至 OOM
显存放置PCIe、GPU 拓扑、并行切分多卡加载慢或某些卡等待
runtime 初始化CUDA、NCCL、kernel 编译或缓存首次请求慢,预热时间长

排查时不要只看 nvidia-smi。如果 GPU 长时间空闲,可能不是 GPU 慢,而是权重还在下载、读盘、解压、反序列化或等待文件锁。

5. safetensors 和分片加载

现在很多模型使用 safetensors 格式,而不是传统 PyTorch .bin 文件。

safetensors 的优势包括:

  • 文件格式更简单,避免任意代码执行风险。
  • 支持按张量读取,适合分片和懒加载。
  • 可以配合 mmap 减少不必要的数据拷贝。
  • 大模型通常按多个 model-00001-of-000xx.safetensors 分片保存。

常见文件结构类似:

model.safetensors.index.json
model-00001-of-00008.safetensors
model-00002-of-00008.safetensors
...
tokenizer.json
config.json

分片不代表一定更快。它的好处是便于管理超大模型、并行加载和按设备切分,但实际速度仍取决于:

  • 本地磁盘吞吐。
  • 并发读取数量。
  • 文件系统和网络盘对并发小文件 / 大文件的支持。
  • CPU 反序列化和内存带宽。
  • 推理框架是否真正并行加载。

如果多个进程同时加载同一模型,分片并发读取可能把本地盘或网络盘打满。生产环境里通常要限制同时冷启动的副本数,或提前把模型预热到节点缓存中。

6. Hugging Face cache 和缓存目录

Hugging Face Transformers、Hub、Datasets 等工具默认会把模型下载到用户目录下的缓存中。常见环境变量包括:

环境变量作用
HF_HOMEHugging Face 总缓存根目录
HF_HUB_CACHEHub 模型和数据文件缓存目录
TRANSFORMERS_CACHETransformers 旧版常见缓存变量
HF_DATASETS_CACHEdatasets 数据缓存目录
TORCH_HOMEPyTorch 相关缓存目录

生产环境建议显式设置缓存路径,例如放到本地 NVMe:

export HF_HOME=/data/cache/huggingface
export HF_HUB_CACHE=/data/cache/huggingface/hub

这样做有几个好处:

  • 避免缓存落到系统盘,把 / 撑满。
  • 方便监控模型缓存目录大小。
  • 多个服务可以约定统一缓存位置。
  • 节点重启后仍可复用已下载模型。

需要同时注意权限和并发问题。多个容器或多个用户共享同一缓存目录时,可能出现文件锁等待、权限不一致、半下载文件残留等问题。生产中更稳妥的做法是让模型制品在发布前完成下载和校验,服务启动时只读本地缓存。

7. 网络盘、本地盘和对象存储怎么选

模型文件可以放在本地盘、网络盘、对象存储或镜像里。不同方案没有绝对优劣,关键看启动 SLA、规模和运维方式。

方案优点风险
本地 NVMe启动快,抖动小,不依赖远端实时读取每个节点都要同步模型,占用本地容量
网络盘多节点共享,管理简单metadata 和吞吐可能成为瓶颈,故障影响面大
对象存储适合版本化、归档和跨集群分发首次下载慢,受限于网络、限流和代理
容器镜像内置模型部署制品自包含,离线环境方便镜像巨大,构建和分发慢,版本更新笨重
init container 预拉模型启动流程清晰,模型和服务镜像解耦首次启动仍依赖下载链路

常见生产推荐是把对象存储或模型仓库作为源,把本地 NVMe 作为热缓存:

远端模型仓库负责版本和审计
本地 NVMe 负责快速启动
服务进程只从本地路径加载

这样可以同时兼顾版本管理和启动性能。

8. 多副本服务的模型分发

多副本部署时,最容易忽略的是“同时启动”的冲击。

例如一个 80 GB 模型,如果 20 个副本同时从同一个远端仓库下载,就会产生 1.6 TB 的短时间读取和网络传输。即使单个副本加载速度可以接受,集群级别也可能把对象存储、网络盘、NAT 网关或节点磁盘打爆。

常见优化方式:

  • 分批滚动发布,限制同时冷启动的副本数。
  • 在节点准备阶段预拉模型,而不是让业务进程启动时下载。
  • 使用本地镜像仓库或模型缓存代理。
  • 在同一节点上复用本地模型目录。
  • 对模型文件做 checksum 校验,避免重复下载损坏文件。
  • 保留最近几个稳定版本,便于快速回滚。

发布系统要把“模型下载完成”和“服务 readiness”分开看。服务端口打开不代表模型已加载完成;模型文件在本地也不代表 GPU runtime 已经预热完成。

9. 容器镜像是否应该打包模型

是否把模型直接放进容器镜像,取决于环境。

适合打包进镜像的情况:

  • 模型较小。
  • 离线或内网环境无法稳定访问模型仓库。
  • 发布频率低,镜像分发系统足够快。
  • 强调制品自包含和可复现。

不适合打包进镜像的情况:

  • 模型几十 GB 到数百 GB。
  • 模型更新频繁。
  • 多个服务共享同一模型。
  • 镜像仓库、节点拉取和 CI 构建速度已经是瓶颈。
  • 需要灰度多个模型版本或快速回滚。

大模型在线服务里,更常见的做法是:

服务镜像:只包含代码、依赖和启动脚本
模型制品:放在模型仓库、对象存储或节点缓存
部署配置:指定 model path / revision / checksum

这样模型版本和服务代码版本可以独立演进,镜像也不会因为模型变更反复构建。

10. 热加载、冷启动和预热

冷启动指实例从没有模型可用,到完成模型加载并能接收请求。它通常包括:

  1. 拉取镜像。
  2. 下载或挂载模型文件。
  3. 加载权重到内存 / 显存。
  4. 初始化 CUDA、NCCL 和推理框架。
  5. 执行预热请求。
  6. 通过 readiness 检查。

热加载通常指进程已运行,切换或新增模型版本。它的难点是资源峰值:

  • 新旧模型可能短时间同时占用磁盘、内存和显存。
  • 多模型服务需要处理请求路由和版本隔离。
  • 加载失败时要能回滚到旧模型。
  • tokenizer、prompt 模板和 generation config 也要随模型版本一起切换。

生产环境里通常要把预热作为正式启动的一部分。预热可以提前触发 CUDA context、kernel 编译、显存池初始化、KV Cache 管理器初始化和首个 batch 调度,避免第一个真实用户请求承担全部成本。

11. 常见问题排查

模型首次启动特别慢

可能原因:

  • 模型正在从远端下载,而不是读本地缓存。
  • 缓存目录在系统盘或慢盘上。
  • 网络代理、对象存储或模型仓库限流。
  • 容器每次重建后缓存丢失。
  • 多个副本同时下载同一模型。

处理方向:

  • 固定 HF_HOME 或模型缓存目录到本地 NVMe。
  • 在部署前预拉模型并校验 checksum。
  • 分批扩容,避免同时冷启动。
  • 监控下载耗时、读盘吞吐和缓存命中率。

模型文件已经在本地,但加载仍然很慢

可能原因:

  • 本地盘是 HDD 或低速网络盘。
  • safetensors 分片很多,metadata 或并发读取慢。
  • CPU 反序列化、内存带宽或 PCIe 传输成为瓶颈。
  • 推理框架初始化或 kernel 预热耗时。
  • 多个进程同时加载同一份权重。

处理方向:

  • 区分下载耗时、读盘耗时、反序列化耗时和显存放置耗时。
  • 使用本地 NVMe。
  • 限制并发启动数量。
  • 给系统内存留出加载峰值冗余。
  • 增加明确的启动阶段日志。

缓存目录越来越大

可能原因:

  • 多个模型 revision 长期保留。
  • 量化版本、LoRA 版本和原始版本同时存在。
  • 临时下载文件或失败残留没有清理。
  • 多个框架各自维护缓存目录。

处理方向:

  • 统一缓存根目录。
  • 定期清理不再使用的模型版本。
  • 保留可回滚版本,不保留无限历史。
  • 对缓存目录设置容量监控和告警。

网络盘偶发加载失败

可能原因:

  • 网络盘吞吐或 metadata 服务抖动。
  • 多副本同时启动造成读放大。
  • 文件锁、权限或挂载参数不一致。
  • 网络盘短暂不可用导致读取中断。

处理方向:

  • 生产推理优先从本地缓存加载。
  • 网络盘作为分发源或共享源,而不是每次启动的直接热路径。
  • 对模型文件做完整性校验。
  • readiness 检查必须覆盖模型加载结果。

12. 选型建议

不同场景的存储策略可以粗略这样选:

场景建议
个人学习SATA SSD 或 NVMe,显式设置模型缓存目录
单机推理服务本地 NVMe 保存模型,避免每次启动重新下载
多副本在线服务远端模型仓库 + 节点本地缓存 + 分批滚动发布
Kubernetes 部署init container 预拉模型,业务容器只读本地挂载
离线内网部署可以考虑镜像内置小模型,大模型更适合独立制品分发
训练 / 微调高吞吐共享存储或并行文件系统,并规划 checkpoint 容量

一个实用原则是:

模型版本用远端仓库管理,模型启动用本地高速盘承载。

13. 总结

存储不会直接替代 GPU 算力,但会决定模型服务能不能快速、稳定、可重复地启动。

判断存储方案时,可以按这几个问题检查:

  1. 模型首次下载和二次启动分别需要多久。
  2. 模型缓存是否落在可控、可监控、容量足够的目录。
  3. 多副本同时启动时,远端仓库、网络和本地盘是否会被打满。
  4. 容器镜像和模型制品是否解耦。
  5. 模型版本、checksum、回滚和缓存清理是否有明确机制。
  6. readiness 是否真正代表模型加载和预热完成。

真正可靠的部署,不是让每个实例临时去网上找模型,而是让模型分发、缓存、加载和预热都成为发布流程中的显式步骤。