arganzheng · 2026-09-22
平台的每一个设计决定都是被引擎的某个需求推出来的,而每个决定都有代价。
| Kubernetes 的假设 | AI 负载怎样违背 | 于是有了 |
|---|---|---|
| Pod 独立 | 32 卡训练要么全起要么都不起 | Kueue / Volcano 的 gang |
| 资源可细分 | GPU 是不透明整数 | device plugin、MIG / HAMi、DRA |
| 一张 overlay 网卡 | NCCL 要 RDMA | Multus、RDMA device plugin、GDR |
| HPA 看 CPU | 推理看 KV 占用与队列 | LeaderWorkerSet、InferencePool、DCGM 映射 |
每篇同一个骨架:引擎的需求 → K8s 的空缺 → 平台的机制 → 代价与边界;每一层都填一个洞,也都挖一个新的。
%%{init: {"flowchart": {"wrappingWidth": 160}}}%%
flowchart LR
P1["01 需求与架构"]
subgraph RES["资源层"]
direction LR
P2["02 GPU·容器"] --> P3["03 调度"] --> P4["04 共享"] --> P5["05 网络·存储"]
end
subgraph DEL["交付层"]
direction LR
P6["06 Serving"] --> P7["07 网关"] --> P8["08 观测"]
end
P1 --> P2
P1 --> P6
P4 & P5 -.-> P6
训练 15 条满足 1 条、推理满足 2 条——GPU 是不透明整数
| 80 GB 卡 × 0.92 可用 | 权重 | 留给 KV |
|---|---|---|
| 7B | 14 GB | 约 60 GB |
| 30B | 60 GB | 约 14 GB |
Insufficient nvidia.com/gpu 说明卡不够」——调度器把「键不存在」与「等于 0」当同一回事;是没有组件把 GPU 上报给 kubelet向后兼容无条件;forward 只有数据中心 GPU + cuda-compat
| 问题 | 答案 |
|---|---|
| 驱动 580 + CUDA 13.1 镜像 + 调用 13.1 新 API | 能跑(规则一) |
| 驱动 570 + CUDA 13.1 镜像 | 13.x 基线是 580.65.06——不行,除非数据中心卡 + cuda-compat |
| 基线 | 12.x ≥ 525.60.13;13.x ≥ 580.65.06 |
| 错误码 | 35 驱动太旧 / 36 API 不支持 / 222 PTX 版本 |
resource.k8s.io/v1 自 1.34 GA 才有属性与共享nvidia-smi 与 torch.version.cuda 不一致就有问题」——前者是驱动上限,后者是 Toolkit 版本gang 只能在调度 / 准入层做——已起的 Pod 占卡等同伴
| A、B 各 16 卡配额,A 提交 32 卡,B 空闲 | 结果 |
|---|---|
| Volcano | 借 B 的 16 卡起;B 回来时默认 actions 不含 reclaim——不还 |
| Kueue | cohort 借用起;默认 reclaimWithinCohort: Never——不还 |
| Slurm | 排队等 A 自己的配额 |
guarantee ≤ deserved ≤ capability;Kueue:nominalQuota / borrowingLimit / lendingLimit + 三个抢占开关时间片无隔离、HAMi 故障域整卡、MIG 硬隔离但刚性——训练不切
| 方式 | 算力隔离 | 显存隔离 | 故障域 | 弹性 |
|---|---|---|---|---|
| 时间片 | 无 | 无(OOM 蔓延) | 整卡 | 任意 N |
| MPS | 软 | 软 | 整卡 | 任意 |
| HAMi | 软(拦截 kernel) | 软(拦截 cudaMalloc,不切带宽与 L2) |
整卡 | deviceSplitCount 默认 10 |
| MIG | 硬 | 硬 | slice(Xid 隔离) | 几何刚性 |
3g.20gb = (3/7) 算力 + (4/8) 带宽;3g.20gb × 2 已用尽 8 个显存 slice——塞不进 1g.5gb,浪费 1 个计算 slice容器 nccl-tests 只有裸机 1/3——三层任一缺项都不报错
| checkpoint I/O:70B、14 字节 / 参数 ≈ 1 TB | 带宽 |
|---|---|
| 30 分钟一次、同步 1 分钟写完 | 聚合 16.7 GB/s、每节点 2.1、每 rank 260 MB/s |
| 异步 | 0.56 GB/s;代价每节点约 125 GB pinned 内存 |
NCCL_DEBUG=INFO 看 Using network IB/Socket 与 /GDRDMA;NCCL_NET_GDR_LEVEL 默认 PXBdcp.async_save领先指标是 running 与 KV 占用;反应式阈值 = 峰值过配
| TP=4 的 70B,晚高峰 2 → 6 副本,就绪 8 分钟 | 结果 |
|---|---|
| 反应式阈值 36 / 副本(饱和点 64 的 56%) | 峰值 10 副本而非 6 |
| cron 提前 12 分钟 + running 56 + waiting 4 + 缩容 15 分钟窗口 | ≈ 5 卡时 / 天 |
| 常驻 6 副本 | 328 卡时 / 天 |
| 信号延迟 | 约 1 分钟 |
EPP 严格优先、同级轮询、无权重公平
| 量 | 数 |
|---|---|
| EPP 打分权重 | 前缀亲和 3、队列 2、KV 2、LoRA 1;每 50 ms 抓一次 /metrics |
| 64 会话 × 8k 对 4 副本 × 160k | 前缀亲和让 TTFT 从 0.5 s 级到几十 ms |
| TPM 预扣 | 输入估算 + min(max_completion_tokens, 上限) |
GPU_UTIL 只表示「有 kernel 在跑」——自旋也算 100%
| 50 个点 | 去向 | 对应篇 |
|---|---|---|
| ~15 | 推理低峰 | 06 |
| ~10 | dev 环境占着不用 | 04 |
| ~10 | 通信等待 | 05 |
| ~5 | 排队占位(gang 半起) | 03 |
| ~3 | checkpoint | 05 |
| ~2 | 冷启动 | 02 |
| ~5 | 测量上限 | — |
| 空缺 | 机制 | 新的洞 |
|---|---|---|
| GPU 是不透明整数 | device plugin | 无属性、不共享 → DRA |
| Pod 独立 | gang(Kueue / Volcano) | 借了不还、30/32 死锁 |
| 一张卡太大 | MIG / HAMi / 时间片 | 几何刚性 / 故障域整卡 / OOM 蔓延 |
| overlay 网卡 | Multus + RDMA plugin | 三层任一缺项静默回落 |
| HPA 看 CPU | KV / running 指标 + cron | 反应式过配 |
| 一个模型一个服务 | 网关 + EPP | 无加权公平 |
| 利用率一个数 | A × U、按分配计费 | GPU_UTIL 骗人 |
Insufficient nvidia.com/gpu 说明卡不够」——没装 device pluginnvidia-smi 与 torch.version.cuda 不一致就有问题」——驱动上限 vs Toolkit 版本SM_ACTIVE| 篇 | 一个数 / 一个判据 |
|---|---|
| 01 | 15 条满足 1 / 2 条;扩容 5–10 分钟 |
| 02 | 12.x ≥ 525.60.13、13.x ≥ 580.65.06;错误码 35 / 36 / 222 |
| 03 | guarantee ≤ deserved ≤ capability;默认借了不还 |
| 04 | 7 计算 / 8 显存 slice;3g.20gb × 2 只放两个 |
| 05 | 同步 16.7 GB/s vs 异步 0.56;NCCL_DEBUG=INFO |
| 06 | 阈值 36 → 10 副本;cron 5 卡时 vs 常驻 328 |
| 07 | 打分 3 / 2 / 2 / 1;每 50 ms |
| 08 | E ≈ A × U;U 40% 贵 2.5 倍 |
/ai-platform-engineering.html;通关自测在系列总结