云原生 AI 的数据存储瓶颈:从训练集到检查点该怎么设计

2026-07-09 36 预计阅读时间: 1 分钟
来源: cncf.io AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:8 分钟

把 AI/ML 工作负载搬进云原生基础设施,真正难的往往不是把容器跑起来,而是让数据持续、稳定、高吞吐地喂给计算资源。CNCF 关于云原生 AI 数据存储的白皮书聚焦的正是这个问题:AI/ML 是数据密集、强状态的工作负载,规模化部署时很容易被存储、网络和数据生命周期管理拖住。

AI 工作负载为什么不像普通微服务

传统无状态服务通常关心请求延迟、弹性扩缩容和故障恢复。AI/ML 工作负载还要额外处理几类“重数据”:

  • 训练数据集:可能是 TB 到 PB 级对象、图片、文本、日志或特征数据。
  • 模型检查点:训练过程中频繁写入,用于恢复、调参和版本管理。
  • 中间产物:特征缓存、预处理结果、评估输出。
  • 推理数据:在线请求、批处理输入、向量索引或模型权重。

这些数据不是容器重启后可以丢弃的临时状态。训练任务如果因为存储吞吐不足而让 GPU 空转,成本会直接放大;检查点写入如果不可靠,长时间训练失败后的恢复成本也会很高。

云原生存储需要同时满足三件事

在 Kubernetes 上跑 AI/ML,存储设计通常要同时回答三个问题。

第一,数据在哪里。对象存储适合大规模数据集和归档,块存储适合单节点高性能读写,文件存储适合多 Pod 共享访问。AI 平台经常需要组合使用,而不是押注一种介质。

第二,数据怎么靠近计算。训练任务经常以短生命周期 Pod 的形式调度,如果每次都从远端拉取完整数据集,启动时间和网络成本会失控。缓存、预取、数据分片和拓扑感知调度会变得重要。

第三,状态如何治理。模型、数据集和检查点都需要版本、权限、保留策略和可追溯性。云原生给了我们声明式 API 和自动化控制面,但也要求团队把存储策略写进平台能力,而不是靠人工约定。

可以这样实践:给训练任务声明持久卷和检查点目录

下面是一个可以改造的 Kubernetes 示例。它展示了一个训练 Job 如何挂载持久卷,把模型检查点写到稳定路径。你需要根据自己的集群替换 storageClassName、镜像地址和训练命令。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ai-checkpoints-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 200Gi
---
apiVersion: batch/v1
kind: Job
metadata:
  name: image-training-job
spec:
  backoffLimit: 2
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: trainer
          image: ghcr.io/example/ml-trainer:latest
          command:
            - python
            - train.py
            - --data-dir=/mnt/dataset
            - --checkpoint-dir=/mnt/checkpoints
          resources:
            limits:
              nvidia.com/gpu: "1"
              cpu: "8"
              memory: 32Gi
            requests:
              cpu: "4"
              memory: 16Gi
          volumeMounts:
            - name: checkpoints
              mountPath: /mnt/checkpoints
            - name: dataset
              mountPath: /mnt/dataset
              readOnly: true
      volumes:
        - name: checkpoints
          persistentVolumeClaim:
            claimName: ai-checkpoints-pvc
        - name: dataset
          persistentVolumeClaim:
            claimName: ai-dataset-pvc

应用前可以先检查当前集群有哪些 StorageClass:

kubectl get storageclass
kubectl apply -f training-storage.yaml
kubectl get job image-training-job
kubectl logs job/image-training-job -f

这个例子不等于完整 AI 平台,但它抓住了一个关键原则:训练代码不应该把检查点写在容器本地文件系统里。Pod 被重调度、节点故障或任务重试时,本地状态很容易丢失。

可以这样实践:把数据准备阶段和训练阶段拆开

数据瓶颈经常不是训练代码本身造成的,而是所有任务同时从远端读取、解压、转换。可以把数据准备拆成单独 Job,先把预处理结果落到共享卷或对象存储,再让训练任务读取稳定格式。

apiVersion: batch/v1
kind: Job
metadata:
  name: prepare-training-data
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: prepare
          image: python:3.12-slim
          command:
            - sh
            - -c
            - |
              python - <<'PY'
              from pathlib import Path
              out = Path('/mnt/prepared')
              out.mkdir(parents=True, exist_ok=True)
              (out / 'manifest.txt').write_text('sample-001.jpg\nsample-002.jpg\n')
              print('prepared dataset manifest')
              PY
          volumeMounts:
            - name: prepared-data
              mountPath: /mnt/prepared
      volumes:
        - name: prepared-data
          persistentVolumeClaim:
            claimName: ai-prepared-data-pvc

实际环境里,这个阶段可以做格式转换、索引生成、样本清洗或特征计算。重点是让昂贵的数据准备动作可复用、可观测、可重试,而不是散落在每个训练容器的启动脚本里。

选型时别只看容量

AI/ML 存储选型很容易从“够不够大”开始,但生产环境更应该问这些问题:

  • 吞吐是否能跟上 GPU 消耗数据的速度?
  • 多个训练任务并发读取同一数据集时,延迟会不会抖动?
  • 检查点写入失败时,任务是失败、重试,还是产生不完整文件?
  • 数据集、模型和检查点有没有版本与保留策略?
  • 存储权限是否和 Kubernetes 身份、命名空间、团队边界匹配?
  • 跨区域、跨集群训练时,复制成本和一致性边界是否清楚?

落地建议

不要把 AI/ML 云原生化理解成“给训练脚本套一个容器”。更稳妥的路径是先识别数据流:数据集从哪里来,预处理在哪里发生,训练如何读取,检查点写到哪里,模型如何交付给推理服务。

小规模阶段可以用 PVC、对象存储和简单 Job 编排把路径跑通;规模变大后,再引入缓存、数据版本管理、拓扑调度和更细的权限治理。核心目标始终是一个:让计算资源等数据的时间越来越少,让状态恢复和数据追踪越来越确定。


相关推荐