K8s AI 调度账:GPU 共享、拓扑感知与弹性伸缩
Slurm 管批任务、K8s 管微服务——但 AI 训练/推理跑在 K8s 上时,"GPU 怎么分、分给谁、放哪张卡"成了核心问题。本文把 K8s AI 调度的三笔账算清:资源抽象、拓扑感知、弹性伸缩,衔接 K8s GPU 调度实战。
1. 资源抽象账:从整卡到碎片
K8s 原生把 GPU 当"整数资源",AI 场景需要三种抽象:
| 抽象层 | 机制 | 粒度 | 典型实现 |
|---|---|---|---|
| 整卡分配 | Device Plugin + 扩展资源 | 1 卡起步 | NVIDIA Device Plugin |
| 显存切分 | MIG / vGPU | 卡内切片 | MIG、虚拟化 |
| 时间片共享 | GPU 时间片复用 | 多 pod 同卡 | 时间片插件 |
判断:整卡分配最简单(隔离好、无争抢);显存切分适合"大卡小模型"的碎片场景;时间片共享适合延迟不敏感任务,但有争抢风险(见 GPU 切分 MIG 与 CUDA MPS)。
2. 拓扑感知调度账:卡放不对,通信白搭
多卡训练对"卡-节点-交换机"的相对位置极度敏感(见 拓扑与通信账):
Pod 请求 8 卡
├─ 同节点 8 卡(NVLink/PCIe,最优)
├─ 同机架 2 节点 × 4 卡(跨节点,次优)
└─ 跨机架 4 节点 × 2 卡(跨交换机,最差)K8s 的解法:
- 节点级:节点标签 + nodeSelector / 亲和性,把训练 pod 钉到同一节点池;
- Pod 级:Pod 间拓扑约束(topologySpreadConstraints),让 8 卡尽量聚在一处;
- 调度器级:Volcano / 拓扑感知调度器,按"GPU 拓扑 + 网络距离"联合打分。
判断:多卡训练必须用拓扑感知手段(标签/亲和/调度器),否则集合通信跨交换机放大延迟;参考 集合通信账 的流量模型评估损失。
3. 弹性伸缩账:推理要弹,训练要稳
| 场景 | 伸缩策略 | 关键约束 |
|---|---|---|
| 推理(在线) | HPA / KEDA 按 QPS、GPU 利用率伸缩 | 冷启动秒级-分钟级,需预热 |
| 训练(批任务) | 队列 + 优先级 + 抢占 | 任务中途缩容=断点重训,谨慎 |
判断:推理适合弹性伸缩,训练不适合——训练弹性的价值在"碎片时间塞小任务",要靠队列(Volcano Queue / Kueue)做公平调度与优先级抢占,而不是粗暴伸缩。
4. 与 Slurm 的定位差异
| Slurm | K8s | |
|---|---|---|
| 模型 | 批任务队列(作业-分区-QOS) | 声明式 Pod/Deployment |
| GPU 切分 | MIG/vGPU 手动绑定 | Device Plugin 统一上报 |
| 弹性 | 弱(任务粒度) | 强(HPA/KEDA) |
| 生态 | HPC 传统栈 | 微服务/云原生栈 |
判断:训练优先 Slurm(稳定、队列成熟,见 Slurm 用户指南),推理优先 K8s(弹性、滚动发布,见 K8s + vLLM 生产)——两者共存是智算中心的常态。
5. 可复算 Python:拓扑收益估算
python
def topology_comm_penalty(n_gpus_per_node, n_nodes, bw_nvlink_gbps, bw_net_gbps, msg_mb):
"""8卡AllReduce:同节点 vs 跨节点的通信耗时(ms,近似)"""
intra = msg_mb * (n_gpus_per_node - 1) / (bw_nvlink_gbps / 8) / 1e3
inter = msg_mb * (n_nodes - 1) / (bw_net_gbps / 8) / 1e3
return round(intra, 2), round(inter, 2)
topology_comm_penalty(8, 2, 400, 200, 16)
# 同节点 0.28 ms vs 跨节点 1.2 ms → 跨节点通信 ≈ 4.3× 耗时
# 提示:卡数>单节点容量时,优先同机架聚合,避免跨交换机6. 交付清单
- 训练 pod 一律用节点亲和把 8 卡钉在同一节点/机架;
- 推理用 HPA/KEDA 弹性伸缩 + 预热池;训练用队列 + 优先级,别中途缩容;
- 碎片显存场景评估 MIG/切分,时间片共享仅限延迟不敏感任务;
- 8 卡以上多节点训练,用 Volcano/拓扑调度器按网络距离打分;
- 上线后实测通信占比(见 通信账)与调度成功率。
本文为本站整理思考后撰写,用于知识库学习交流;公式与算例为本站自行推导整理,具体版本与实测数据以现场为准。