别只盯着 GPU:生产级 AI 平台是一套异构计算系统

2026-09-04 29 预计阅读时间: 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.

预计阅读时间:7 分钟

谈到 AI 基础设施,GPU 往往最先进入讨论:需要多少张卡、显存多大、训练吞吐是多少。但生产工作负载并不是把张量送入 GPU 就结束了。数据读取、解压、清洗、分词、请求编排、结果后处理和可观测性通常运行在 CPU 上,并持续依赖内存、网络与存储。平台工程真正要解决的,是这些资源如何协同,而不只是如何分配加速卡。

GPU 利用率低,不一定是 GPU 的问题

一条典型的推理链路可以拆成以下阶段:

  1. 网关接收请求并完成鉴权、限流和批次组织。
  2. CPU 执行图像解码、特征转换或文本分词。
  3. 数据通过主机内存进入设备内存。
  4. GPU 执行模型计算。
  5. CPU 完成采样、格式化、过滤和响应序列化。

只要其中一个阶段跟不上,GPU 就会等待。此时继续增加 GPU,可能只会增加昂贵的空闲容量。例如,数据加载器受存储延迟影响、分词线程耗尽 CPU,或者请求尺寸差异过大导致动态批处理效率下降,都可能表现为 GPU 利用率波动。

因此,容量规划不能只记录 GPU 数量。至少还应观察:

  • CPU 使用率、节流时间和运行队列长度
  • 主机内存、锁页内存与设备内存占用
  • 存储吞吐、IOPS 和读取延迟
  • 节点间网络吞吐及重传
  • 队列等待时间、批次大小和端到端延迟
  • GPU 利用率、显存占用及数据传输时间

这些指标需要按同一个请求、作业或模型版本关联起来。单独看到 GPU 利用率只有 40%,并不能直接得出应该缩容的结论。

把不同阶段放进不同资源池

将预处理、模型执行和后处理全部塞进一个申请 GPU 的 Pod,部署简单,却容易造成资源绑定:只要 CPU 阶段变慢,Pod 占用的 GPU 仍无法交给其他任务。更可控的设计是用队列或 RPC 边界拆分阶段,让它们独立扩缩容。

可以这样实践,以下示例假设集群已经安装 NVIDIA device plugin,并存在标记为 workload=cpuworkload=gpu 的节点。镜像名和启动命令需要替换为实际应用:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ai-preprocessor
spec:
  replicas: 4
  selector:
    matchLabels:
      app: ai-preprocessor
  template:
    metadata:
      labels:
        app: ai-preprocessor
    spec:
      nodeSelector:
        workload: cpu
      containers:
        - name: worker
          image: example.com/ai-preprocessor:1.0
          args: ["--input-queue=raw", "--output-queue=ready"]
          resources:
            requests:
              cpu: "2"
              memory: 4Gi
            limits:
              cpu: "4"
              memory: 8Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ai-inference
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ai-inference
  template:
    metadata:
      labels:
        app: ai-inference
    spec:
      nodeSelector:
        workload: gpu
      containers:
        - name: server
          image: example.com/ai-inference:1.0
          args: ["--input-queue=ready", "--batch-size=16"]
          resources:
            requests:
              cpu: "8"
              memory: 32Gi
              nvidia.com/gpu: "1"
            limits:
              cpu: "8"
              memory: 32Gi
              nvidia.com/gpu: "1"

部署前可先进行服务端校验:

kubectl apply --dry-run=server -f ai-workers.yaml
kubectl apply -f ai-workers.yaml
kubectl get pods -o wide
kubectl top pods

这种拆分允许 CPU worker 根据输入队列深度扩容,GPU worker 根据待推理批次数、延迟目标和设备利用率扩容。代价也很明确:平台需要维护队列语义、重试、幂等性、超时和跨阶段追踪。对于低流量或极低延迟服务,额外的网络跳转可能不值得,此时同 Pod 部署仍可能更合适。

调度器看到资源,平台还要理解拓扑

Kubernetes 的资源请求能表达需要一张 GPU,却不自动保证数据、CPU、内存和 GPU 之间的路径高效。NUMA 布局、PCIe 拓扑、本地缓存、共享文件系统和节点间网络都可能改变实际吞吐。

平台团队可以把这些约束转化为可操作的能力:维护具有明确标签和污点的节点池;为训练、在线推理和批处理设置不同优先级;用拓扑感知调度减少不必要的数据搬运;避免让数据准备任务长期占用 GPU 节点;同时为 CPU 和 GPU 镜像建立一致的驱动、运行时及模型版本管理流程。

扩缩容信号也应贴近瓶颈。CPU 预处理适合参考队列深度和处理速率,在线推理更适合结合排队延迟、批次填充率与 GPU 利用率。仅以 CPU 百分比驱动整条 AI 链路,通常无法准确反映加速器是否饱和。

落地时先回答五个问题

在采购更多 GPU 或调整实例规格之前,建议逐项确认:

  • 每个请求在 CPU、GPU、网络和存储阶段分别花费多长时间?
  • GPU 等待的是计算、数据,还是批次凑齐?
  • CPU 与 GPU 阶段能否独立扩缩容,拆分后的延迟成本是多少?
  • 调度策略是否考虑数据位置、设备拓扑和故障域?
  • 性能回归能否定位到模型版本、数据版本和基础设施变更?

GPU 是 AI 平台最显眼也最昂贵的资源,但平台效率取决于整条流水线。成熟的容量决策不是单纯追求更高的 GPU 利用率,而是在吞吐、尾延迟、可靠性和单位请求成本之间建立可测量、可调整的平衡。


相关推荐