谈到 AI 基础设施,GPU 往往最先进入讨论:需要多少张卡、显存多大、训练吞吐是多少。但生产工作负载并不是把张量送入 GPU 就结束了。数据读取、解压、清洗、分词、请求编排、结果后处理和可观测性通常运行在 CPU 上,并持续依赖内存、网络与存储。平台工程真正要解决的,是这些资源如何协同,而不只是如何分配加速卡。
GPU 利用率低,不一定是 GPU 的问题
一条典型的推理链路可以拆成以下阶段:
- 网关接收请求并完成鉴权、限流和批次组织。
- CPU 执行图像解码、特征转换或文本分词。
- 数据通过主机内存进入设备内存。
- GPU 执行模型计算。
- CPU 完成采样、格式化、过滤和响应序列化。
只要其中一个阶段跟不上,GPU 就会等待。此时继续增加 GPU,可能只会增加昂贵的空闲容量。例如,数据加载器受存储延迟影响、分词线程耗尽 CPU,或者请求尺寸差异过大导致动态批处理效率下降,都可能表现为 GPU 利用率波动。
因此,容量规划不能只记录 GPU 数量。至少还应观察:
- CPU 使用率、节流时间和运行队列长度
- 主机内存、锁页内存与设备内存占用
- 存储吞吐、IOPS 和读取延迟
- 节点间网络吞吐及重传
- 队列等待时间、批次大小和端到端延迟
- GPU 利用率、显存占用及数据传输时间
这些指标需要按同一个请求、作业或模型版本关联起来。单独看到 GPU 利用率只有 40%,并不能直接得出应该缩容的结论。
把不同阶段放进不同资源池
将预处理、模型执行和后处理全部塞进一个申请 GPU 的 Pod,部署简单,却容易造成资源绑定:只要 CPU 阶段变慢,Pod 占用的 GPU 仍无法交给其他任务。更可控的设计是用队列或 RPC 边界拆分阶段,让它们独立扩缩容。
可以这样实践,以下示例假设集群已经安装 NVIDIA device plugin,并存在标记为 workload=cpu 和 workload=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 利用率,而是在吞吐、尾延迟、可靠性和单位请求成本之间建立可测量、可调整的平衡。