一句话结论:控制面决定「能不能跑」,数据面决定「跑多快」。K8s 的功夫全在控制面——把 Pod 调度起来、把副本数维持住;而大模型训练真正的痛点,是 GPU 之间、机器之间的数据流动快不快、堵不堵。kubectl get pods 全绿但 MFU 上不去,是典型的控制面看不见的数据面问题。

本文基于 B 站视频《K8s 很熟,为什么月薪卡在三万?大模型 AI Infra 第一讲:从控制面走到数据面》的内容框架整理,其中的技术细节我对照 NVIDIA 官方文档(nvidia-smi 拓扑定义、NCCL 环境变量文档)与相关论文做了核实与补全。核对过程中发现原稿有四处需要更正的地方,已在文中标注。


一、为什么 K8s 玩得溜,月薪却卡在三万

很多云原生工程师 K8s 炉火纯青:写 YAML、调 Deployment、写 Operator、排 Pod 故障、扩缩集群,整套控制面技术一气呵成,但薪资天花板死死卡在三万上下。而那些看起来「只是会跑 nccl-tests」的 AI Infra 同事,年薪轻松翻倍。

差距不在于会不会写 YAML,而在于是否看懂了 K8s 之下的数据面。

一个常见的生产现象:kubectl get pods 一切 Running、GPU device plugin 正常上报、Prometheus 没有告警——但训练 MFU(Model FLOPs Utilization)就是上不去。这就是典型的数据面问题。

打个比方:K8s 控制面是高速收费站,数据面才是高速公路本身。收费站显示一切正常,不代表高速上没堵车、没修路、没事故。

四个真实生产案例:K8s 全绿,但训练慢成狗

  1. 走错链路:GPU 已分配、Pod Running,但卡间通信实际走 PCIe 而不是 NVLink,带宽从 900 GB/s 掉到 128 GB/s,直接掉一个数量级;
  2. GDRDMA 没生效:跨节点 RDMA 没走 GPUDirect,流量在 CPU 内存中转,延迟翻倍、带宽下降 30—50%,K8s 监控完全无感;
  3. 交换机端口缓存拥塞:没丢包,但 PFC/ECN 配错导致 AllReduce 同步延迟飙升,常见于 RoCEv2 网络调优不当;
  4. 拓扑异构选路错:集群里混插了不同代次的机器,NCCL 自动选路把跨节点流量绕到远端网卡,整机带宽被拖低。

上面四类问题,kubectl describe 里全部看不到异常。


二、大厂 AI Infra 岗位到底在考察什么

面试很少死磕 YAML 语法,核心只有一句话:

数据在 GPU 卡与卡、机器与机器之间是怎么流动的?流动堵塞、抖动、变慢时,你如何定位?

维度 传统云原生(控制面) AI Infra(数据面)
关注对象 API 对象、Pod 生命周期、调度器、RBAC、CRD NVLink / NVSwitch、PCIe、RDMA、NCCL 集合通信
健康定义 Pod Running、探针通过、副本数正确 链路带宽跑满、集合通信不阻塞、MFU 达标
排查工具 kubectl、etcdctl、Prometheus、Grafana nvidia-smi topo、NCCL_DEBUG、nccl-tests、ib_write_bw、DCGM
「慢」的定义 QPS 下降、P99 抖动 任何一张卡的任何一次梯度交换被拖慢

三、AllReduce 与可怕的木桶效应

3.1 集合通信原语速览

假设 4 张卡分别持有 A、B、C、D 四段数据:

原语 输入 输出 用途
Reduce 各卡持有不同分片 仅 root 卡持有 A+B+C+D 单点汇总
All-Reduce 各卡持有不同分片 所有卡都持有 A+B+C+D 梯度同步(最常用)
Gather 各卡持有不同分片 仅 root 卡拼出 [A,B,C,D] 单点收集
All-Gather 各卡持有不同分片 所有卡都持有 [A,B,C,D] 流水线并行激活传递
Scatter 仅 root 持有 [A,B,C,D] 各卡分别持有 A/B/C/D 数据切分下发
Reduce-Scatter 各卡持有分片矩阵 第 i 卡持有第 i 列的和 Ring AllReduce 第一阶段

关键恒等式:All-Reduce = Reduce-Scatter + All-Gather。这是理解 Ring 算法的入口。

3.2 Ring AllReduce:每卡只需传约 2 倍数据

NCCL 默认的 Ring 算法把 N 张卡首尾连成一个逻辑环,每张卡的数据切成 N 块:

  1. 前 N-1 轮(Reduce-Scatter):每轮只向右邻居发一块、从左邻居收一块并累加;
  2. 后 N-1 轮(All-Gather):把累加好的块继续沿环分发,最终每张卡都拿到完整结果。

总轮数 2(N-1),每轮传输量 S/N,所以每张卡的发送总量 ≈ 2(N-1)/N × S:

N 每卡发送量 / 数据量
8 1.75×
64 1.97×
1024 ≈ 2×

核心收益:卡数再怎么增加,每卡通信量收敛到 2×,不会成倍暴涨。这就是 Ring 算法能扩展到千卡集群的数学基础。

代价是强同步:每一轮都必须等邻居把数据送到才能继续。

3.3 木桶效应:一张卡慢,全体跟着慢

Ring AllReduce 是环形的、强同步的。视频里那张「卡在第 3 轮」的截图非常形象——GPU 3 标红「慢」,其他 7 张卡全部停在等待状态。

两个生活化类比:外卖骑手(必须最慢那位全部送达,本轮才算结束)、赛艇团队(整条艇的速度取决于划桨最慢的那个人)。

核心结论:千卡集群里,只要有一张卡慢 30%,整个训练任务就慢 30%。

这与传统分布式业务完全不同。Web 服务里一个实例变慢,只影响分摊到它身上的少量请求;而大模型训练是强同步系统,AllReduce 强制所有 GPU 互相等待。

反直觉之处:传统思维是「个别节点慢只影响局部」。在 AI 集群里,任何局部劣化都会被强同步机制放大成全集群性能灾难。这是控制面工程师最容易踩的认知盲区。


四、一条命令看懂数据面:nvidia-smi topo -m

K8s 层面看不出问题时,必须直接看硬件拓扑。这是数据面排查的第一把钥匙。

4.1 缩写 = 距离:从近到远

矩阵里每个缩写,本质是在描述两个设备之间的物理距离。以下是 NVIDIA 官方文档的原始定义(我逐条对照过,不是转述):

缩写 NVIDIA 官方定义 是否经 Host Bridge 典型出现位置
NV# Connection traversing a bonded set of # NVLinks ❌ GPU ↔ GPU(HGX 机型)
PIX Connection traversing a single PCIe switch ❌ GPU ↔ 同 Switch 网卡
PXB Connection traversing multiple PCIe switches (without traversing the PCIe Host Bridge) ❌ Switch 级联机型
PHB Connection traversing PCIe as well as a PCIe Host Bridge (typically the CPU) ✅ 设备直连 CPU 根端口
NODE Connection traversing PCIe as well as the interconnect between PCIe Host Bridges within a NUMA node ✅ 同 NUMA 内跨 PCIe Switch
SYS Connection traversing PCIe as well as the SMP interconnect between NUMA nodes(如 QPI/UPI) ✅ + UPI 跨 socket

⚠️ 更正一处:原稿把 NODE 的「是否经过 CPU」标成了 ❌(注释「不过 UPI」)。按 NVIDIA 官方定义,NODE 是 “PCIe as well as the interconnect between PCIe Host Bridges within a NUMA node”——它确实经过 Host Bridge,只是不跨 NUMA 边界、不走 UPI。「不经过 CPU」和「不经过 UPI」是两件事,前者对 NODE 不成立。

距离口诀:NV# 最亲(专用高速底板)→ PIX 同屋 → PXB 同楼层 → PHB 过大门 → NODE 同院不同楼 → SYS 出院跨街。每往下一级,带宽更低、时延更高。

两条机型相关的补充:

  • PXB 只在 PCIe Switch 级联的机型上出现;
  • PHB 只在设备直连 CPU 根端口(不经 PCIe Switch)时出现。

4.2 标准 8 卡 HGX:一台机器,两个并行平面

这是本节最容易被画错的地方。标准 8 卡 HGX 服务器不是两个独立的通信域,而是一台机器上两个并行的平面:

  • PCIe 平面:CPU 0 / CPU 1 通过 UPI 互联,各自挂 2 颗 PCIe Switch,每颗 Switch 下挂 2 张 GPU + 1 张网卡——这条路负责 GPU ↔ 网卡(跨节点通信的进出口);
  • NVLink 底板平面:8 张 GPU 通过 4 颗 NVSwitch 两两全连通,完全不经过 CPU——这条路负责 GPU ↔ GPU(卡间梯度同步)。

这张图要读出三层信息:

  1. GPU ↔ GPU:全部走底部 NVLink 底板(NV#),不管两张卡属于哪个 NUMA,8 卡全连通,完全绕开 CPU 和 UPI——这是大模型训练卡间通信的主跑道;
  2. GPU ↔ 本 Switch 网卡:走 PIX(例如 GPU0 ↔ NIC0),这是跨节点通信最理想的进出路径,也是 GPUDirect RDMA 最容易生效的位置;
  3. GPU ↔ 跨 Switch / 跨 NUMA 网卡:分别对应 NODE 和 SYS,带宽逐级下降。

4.3 拓扑矩阵对照:同一台机器长什么样

把上图转成 nvidia-smi topo -m 的矩阵视角,验证「缩写 = 距离」:

通信对 矩阵符号 走哪条路
GPU0 ↔ GPU1 NV# NVLink 底板(同 Switch,同时也是 NVLink 邻居)
GPU0 ↔ GPU7 NV# NVLink 底板——跨 NUMA 依然走 NVLink,不走 SYS
GPU0 ↔ NIC0 PIX 同一颗 PCIe Switch 内部
GPU0 ↔ NIC1 NODE 同 CPU,跨 PCIe Host Bridge
GPU0 ↔ NIC3 SYS 跨 CPU,走 UPI

关键判据:在这类机型上,GPU↔GPU 的矩阵里永远看不到 PIX/NODE/SYS——因为 NVLink 底板优先级最高,NCCL topo 探测会直接报 NV#。如果你在一张 NVLink 机器的 GPU↔GPU 格子里看到 PIX 或 SYS,说明 NVLink 已降级或未接通,这是重大故障信号。

4.4 对比机型:8 卡 L40S 纯 PCIe 服务器

没有 NVLink 底板的机型,同一套缩写体系读起来完全不一样:

对应的拓扑矩阵:

GPU0 GPU1 GPU2 GPU3 GPU4 GPU5 GPU6 GPU7 CPU Affinity NUMA
GPU0 X PIX NODE NODE SYS SYS SYS SYS 0-55 0
GPU1 PIX X NODE NODE SYS SYS SYS SYS 0-55 0
GPU2 NODE NODE X PIX SYS SYS SYS SYS 0-55 0
GPU3 NODE NODE PIX X SYS SYS SYS SYS 0-55 0
GPU4 SYS SYS SYS SYS X PIX NODE NODE 56-111 1
GPU5 SYS SYS SYS SYS PIX X NODE NODE 56-111 1
GPU6 SYS SYS SYS SYS NODE NODE X PIX 56-111 1
GPU7 SYS SYS SYS SYS NODE NODE PIX X 56-111 1

读这张矩阵的三个要点:

  1. 张量并行横跨 8 张卡时代价惨重:每一层通信都走 PCIe,其中 GPU0-3 与 GPU4-7 之间还要跨过 UPI(SYS);
  2. 可安全放在一起的组合:GPU0-1(PIX,同 Switch)、GPU0-3(同 CPU,NODE)——这是任务摆放的基本约束;
  3. NIC 与 GPU 的亲和性:NIC0 跟 GPU0/1 同 Switch(PIX),NIC1 跟 GPU2/3 是 NODE,NIC3 跟 GPU0 是 SYS——NCCL 会根据这些距离自动决定跨节点流量从哪张网卡出,拓扑异构时选错网卡就是生产事故。

4.5 实操验证命令

不要只信硬件规格书,要在生产环境实测真实链路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. GPU 硬件拓扑矩阵(最基础)
nvidia-smi topo -m

# 2. 卡间 P2P 是否可用(确认 NVLink/NVSwitch 真的接通)
nvidia-smi topo -p2p n

# 3. 看 NCCL 实际选路(验证是否走 NVLink / GDRDMA)
export NCCL_DEBUG=INFO
# 期望:... via P2P/NVL
# 降级:... via P2P/Direct PCI 或 NET/IB/0(缺 /GDRDMA 后缀)

# 4. 跑 all_reduce_perf 验证真实 busbw
# 单节点:all_reduce_perf -b 8 -e 8G -f 2 -g 8
# 多节点:mpirun -np 8 --map-by ppr:1:node all_reduce_perf ...
# 判读:看 busbw 列(不是 algbw);#wrong 必须为 0

常见踩坑:服务器明明是 NVLink 机型,但驱动、固件、BIOS 配置异常导致 NCCL 降级走 PCIe——矩阵里 GPU↔GPU 从 NV# 变成 PIX/SYS。K8s 完全感知不到,只有 topo 矩阵和 NCCL 日志能定位。纸面规格 ≠ 实际链路,这是生产常态。


五、RDMA 与千分之一丢包的灾难

5.1 为什么 RDMA 对丢包零容忍

传统 TCP 丢包,重传是小粒度的,丢 1 个 MSS 也就几 KB。但 RDMA(InfiniBand 和 RoCEv2 都一样)为极致低时延设计,一旦丢包触发的是较大粒度的回退重传,等待时间可达秒级。

为此业界设计了无损以太网,靠三个机制组合:

机制 作用 类比
PFC(Priority Flow Control) 链路级反压,上游端口缓存快满时让上游暂停发包,从源头避免丢包 收费站前方开始堵车,提前在匝道关闸
ECN(Explicit Congestion Notification) 交换机在包上打标记,通知接收端「我开始拥塞了」 收费站广播前方拥堵信息
DCQCN(Data Center QCN) 端到端拥塞控制,根据 ECN 反馈调节发送端速率 司机收到广播后主动减速

PFC/ECN 配错是 RoCEv2 网络最常见的问题——不丢包但 P99 时延抖动,AllReduce 同步延迟飙升。

5.2 千分之一丢包为什么能拖垮千卡训练

  1. RDMA 重传代价巨大:一旦触发大粒度回退重传,等待秒级;
  2. AllReduce 强同步:任何一个报文丢失,所有 GPU 全部停下来等重传完成;
  3. 丢包事件高频发生:千卡集群每秒海量数据包,0.1% 平均丢包率意味着几乎每秒都有卡在重传;
  4. 木桶效应放大:丢包卡的邻居被拖住,邻居的邻居被拖住……故障沿环形拓扑扩散;
  5. 常规监控失明:Prometheus 上的带宽、网卡 error 计数,对 0.1% 级别轻微丢包不敏感。

两个数据点:Meta 在 SIGCOMM 2024 发表的 RoCE 大规模部署论文(RDMA over Ethernet for Distributed AI Training at Meta Scale)强调,AI 训练的 Backend Fabric 必须 non-blocking、lossless、low-latency,并为此配了独立的 AI Zone 网络与前端网络完全隔离。另外,RDMA 容错方向的论文 SHIFT: Exploring the Boundary of RDMA Network Fault Tolerance(arXiv:2512.11094)引用阿里的生产数据指出:网络相关问题占全部生产故障的 15.8%。

⚠️ 注意这个 15.8% 的口径是「全部生产故障」,不是「训练故障」,且是二次引用(SHIFT 引用阿里)。原稿参考列表把这篇论文的标题写成了 An RDMA Failure-Resilient Layer for Distributed Training,实际标题是 SHIFT: Exploring the Boundary of RDMA Network Fault Tolerance,已更正。

5.3 GPUDirect RDMA:从「绕 CPU」到「直通网卡」

跨节点通信的常见坑:流量从 GPU 显存 → CPU 内存 → 网卡,要绕两次 PCIe。GPUDirect RDMA 让网卡直接读写 GPU 显存,省掉 CPU 中转:

路径 时延 带宽 CPU 占用
GPU → NIC(GDRDMA) ~1—2 µs 48—50 GB/s ~0%
GPU → CPU → NIC(staged) ~5—10 µs 25—35 GB/s 高

结合 4.1 的距离表可以看出,GDRDMA 的启用条件本质就是「GPU 和网卡在拓扑上足够近」——PIX 级最理想,NODE 级勉强,SYS 级通常不建议强制开启。

启用与验证:

1
2
3
4
5
6
7
modprobe nvidia-peermem
lsmod | grep nvidia_peermem

export NCCL_DEBUG=INFO
export NCCL_NET_GDR_LEVEL=SYS # 见下方说明
# 生效:... via NET/IB/0/GDRDMA
# 未生效:... via NET/IB/0

5.4 NCCL_NET_GDR_LEVEL 的正确取值(更正一处)

⚠️ 原稿的数值表整体有误,这里按 NVIDIA 官方文档更正。

NCCL 官方的取值是字符串,代表允许启用 GDRDMA 的最远距离:

值(推荐用字符串) 含义 legacy 整数
LOC 从不使用 GPU Direct RDMA 0
PIX GPU 与网卡在同一个 PCIe switch 上 1
PXB GPU 与网卡经多个 PCIe switch 相连(可能多跳) 2
PHB GPU 与网卡在同一个 NUMA node(流量会经过 CPU) 3
SYS 即使跨 NUMA 之间的 SMP 互连也启用(等价于总是启用) 4

三个容易踩的点:

  1. GDR 档位里没有 NODE。nvidia-smi topo 的 NODE 是拓扑分类,而 NCCL_NET_GDR_LEVEL 只有 LOC/PIX/PXB/PHB/SYS 五档——PHB 那一档的官方描述就是「同一个 NUMA node」。原稿把 NODE 列为第 3 档、SYS 列为第 4 档、再发明了一个「5 = Always」,与官方不符。
  2. 不存在「5 = Always」。官方原文:Values greater than 4 will be interpreted as SYS——大于 4 会被当作 SYS 处理,它不是一个独立档位。想「总是启用」就写 SYS。
  3. NCCL 明确不推荐用整数:Integer values are discouraged due to breaking changes in path types — the literal values can change over time. To avoid headaches debugging your configuration, use string identifiers. 用整数可能在版本升级后行为漂移,一律用字符串。

六、K8s 转 AI Infra 的五道物理鸿沟

  1. 调度鸿沟:默认 K8s 调度器把 GPU 当作不透明的整数资源,不知道哪两张卡在同一个 NVLink 域、不知道 NUMA 亲和性。需要 Volcano 这类支持拓扑感知的调度器,把一组 Pod 作为 gang 调度到同一拓扑域。
  2. 网络鸿沟:RDMA、NVLink、NCCL 集合通信,与 K8s 默认 CNI 模型完全不适配。需要 Multus、SR-IOV、RDMA shared device plugin,还要 PFC/ECN 无损网络配合。
  3. 存储鸿沟:大模型需要并行文件系统(Lustre、GPFS、JuiceFS、3FS),高吞吐低延迟,普通 PV/PVC 经常成为数据加载瓶颈。
  4. 虚拟化鸿沟:GPU 透传、vGPU、MIG 切分、多卡共享,与 CPU 容器的 cgroup 隔离逻辑完全不同。
  5. 可观测性鸿沟:MFU、卡间带宽、NCCL 通道日志、RDMA 微抖动、PFC 反压计数——传统 Node/Network 指标体系完全不够用。

七、给 K8s 老兵的转型建议

  1. 跳出 K8s 对象的习惯:遇到性能问题,别只看 Pod、Node、Events,主动向下看硬件拓扑、卡间通信、NCCL 日志;
  2. 吃透集合通信原理:理解 AllReduce、Ring 算法、带宽复杂度 2(N-1)/N、强同步的木桶效应;
  3. 掌握硬件排查工具链:nvidia-smi topo -m、nvidia-smi topo -p2p n、NCCL_DEBUG=INFO、nccl-tests、ib_write_bw、DCGM;
  4. 建立「纸面规格 ≠ 实际链路」的意识:说明书上的 NVLink 900 GB/s、400G 网卡,生产环境会因固件、BIOS、驱动、交换机配置而降级;
  5. 不要把 GPU 当大号 CPU:区分控制面与数据面的关注点。

八、总结

K8s 帮我们把 GPU 资源调度起来,保证任务能跑起来;AI Infra 要做的,是让 GPU 真正跑快。

月薪卡在三万,往往不是 K8s 学得不够深,而是始终停留在控制面世界,缺少对底层硬件、高速通信、数据流动的理解。

一句话作为锚点:下次再看到 Pod Running 却训练慢,先别去看 kubectl,先跑一句 nvidia-smi topo -m,把矩阵里每一个缩写当成一次「物理距离测量」。


相关阅读

核实说明:本文的 nvidia-smi topo 缩写定义、NCCL_NET_GDR_LEVEL 取值与语义,均逐条核对自 NVIDIA 官方文档(nvidia-smi 拓扑说明页、NCCL Environment Variables 页)。15.8% 网络故障数据核对自 arXiv:2512.11094 正文。原稿的四处更正已在文中以 ⚠️ 标注:NODE 的距离等级归属、NCCL_NET_GDR_LEVEL 的档位与整数映射、论文标题、以及拓扑图的一处笔误。