3.2 拓扑感知调度:NVLink、PCIe 与 RDMA 亲和 同样是 8 卡训练,把 8 张卡放在「全 NVLink 互联」的节点上,AllReduce 通信可能比放在「走 PCIe Switch」的节点上快 3-5 倍。调度器如果不懂拓扑,盲目把训练 Pod 撒到任意节点,等于让法拉利跑乡道。拓扑感知调度的任务,就是让分布式训练的通信走最快的路。 3.2.1 多 GPU 节点的拓扑真相 一个 8 卡 GPU 服务器内部,8 张卡并不是「两两等距」的。它们通过几种不同的互联通道连接,每种通道的带宽与延迟差异巨大: NVLink:NVIDIA 专属的高速 GPU 互联,单链路带宽可达 50-300 GB/s(H100 NVLink 4.
同样是 8 卡训练,把 8 张卡放在「全 NVLink 互联」的节点上,AllReduce 通信可能比放在「走 PCIe Switch」的节点上快 3-5 倍。调度器如果不懂拓扑,盲目把训练 Pod 撒到任意节点,等于让法拉利跑乡道。拓扑感知调度的任务,就是让分布式训练的通信走最快的路。
一个 8 卡 GPU 服务器内部,8 张卡并不是「两两等距」的。它们通过几种不同的互联通道连接,每种通道的带宽与延迟差异巨大:
一个典型 8 卡节点的拓扑(示意):
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 880 380" font-family="sans-serif" font-size="12"> <text x="440" y="22" text-anchor="middle" font-size="15" font-weight="bold">8 卡 GPU 节点内部拓扑示意(NUMA + NVLink + IB)</text> <!-- NUMA 0 --> <rect x="20" y="50" width="410" height="200" rx="8" fill="#dbeafe" stroke="#2563eb" stroke-dasharray="4,2"/> <text x="35" y="72" font-weight="bold" fill="#1e40af">NUMA 0(CPU 0 + 本地内存)</text> <g> <rect x="40" y="90" width="80" height="50" rx="4" fill="#fff" stroke="#2563eb"/> <text x="80" y="115" text-anchor="middle">GPU 0</text> <rect x="135" y="90" width="80" height="50" rx="4" fill="#fff" stroke="#2563eb"/> <text x="175" y="115" text-anchor="middle">GPU 1</text> <rect x="230" y="90" width="80" height="50" rx="4" fill="#fff" stroke="#2563eb"/> <text x="270" y="115" text-anchor="middle">GPU 2</text> <rect x="325" y="90" width="80" height="50" rx="4" fill="#fff" stroke="#2563eb"/> <text x="365" y="115" text-anchor="middle">GPU 3</text> <!-- NVLink 横向连接 --> <line x1="120" y1="115" x2="135" y2="115" stroke="#dc2626" stroke-width="2"/> <line x1="215" y1="115" x2="230" y2="115" stroke="#dc2626" stroke-width="2"/> <line x1="310" y1="115" x2="325" y2="115" stroke="#dc2626" stroke-width="2"/> <text x="80" y="170" text-anchor="middle" font-size="10" fill="#dc2626">━ NVLink(极快)</text> <text x="225" y="210" text-anchor="middle" font-size="10" fill="#475569">GPU 0-3 之间全互联 NVLink</text> </g> <!-- NUMA 1 --> <rect x="450" y="50" width="410" height="200" rx="8" fill="#dcfce7" stroke="#16a34a" stroke-dasharray="4,2"/> <text x="465" y="72" font-weight="bold" fill="#15803d">NUMA 1(CPU 1 + 本地内存)</text> <g> <rect x="470" y="90" width="80" height="50" rx="4" fill="#fff" stroke="#16a34a"/> <text x="510" y="115" text-anchor="middle">GPU 4</text> <rect x="565" y="90" width="80" height="50" rx="4" fill="#fff" stroke="#16a34a"/> <text x="605" y="115" text-anchor="middle">GPU 5</text> <rect x="660" y="90" width="80" height="50" rx="4" fill="#fff" stroke="#16a34a"/> <text x="700" y="115" text-anchor="middle">GPU 6</text> <rect x="755" y="90" width="80" height="50" rx="4" fill="#fff" stroke="#16a34a"/> <text x="795" y="115" text-anchor="middle">GPU 7</text> <line x1="550" y1="115" x2="565" y2="115" stroke="#dc2626" stroke-width="2"/> <line x1="645" y1="115" x2="660" y2="115" stroke="#dc2626" stroke-width="2"/> <line x1="740" y1="115" x2="755" y2="115" stroke="#dc2626" stroke-width="2"/> <text x="795" y="170" text-anchor="middle" font-size="10" fill="#dc2626">━ NVLink(极快)</text> </g> <!-- 跨 NUMA --> <line x1="430" y1="115" x2="450" y2="115" stroke="#ca8a04" stroke-width="3"/> <text x="440" y="100" text-anchor="middle" font-size="10" fill="#ca8a04">QPI</text> <text x="440" y="135" text-anchor="middle" font-size="10" fill="#ca8a04">慢</text> <!-- IB 网卡 --> <rect x="350" y="280" width="180" height="50" rx="6" fill="#fce7f3" stroke="#db2777"/> <text x="440" y="310" text-anchor="middle" font-weight="bold">InfiniBand HCA(跨节点)</text> <line x1="225" y1="250" x2="400" y2="280" stroke="#475569" stroke-dasharray="3,3"/> <line x1="650" y1="250" x2="480" y2="280" stroke="#475569" stroke-dasharray="3,3"/> <text x="20" y="355" font-size="11" fill="#475569">关键:GPU 0-3 在同一 NUMA 且 NVLink 全互联 → 通信最快;跨 NUMA 走 QPI 变慢;跨节点走 IB</text> </svg>
这张图揭示了一个关键事实:即使是同一节点内的 8 张卡,通信速度也千差万别。GPU 0 和 GPU 1 之间走 NVLink(极快),GPU 0 和 GPU 4 之间跨 NUMA 走 QPI(慢),GPU 0 和另一节点上的 GPU 走 IB(中等)。
分布式训练最核心的通信原语是 AllReduce(详见第 5 章)——所有 worker 把各自的梯度聚合后广播给所有人。AllReduce 的通信量与拓扑带宽直接相关。
假设一个 8 卡训练,每张卡要把 1GB 梯度做 AllReduce。理论上:
💡 判读:拓扑差异在单次 AllReduce 上看是「快几倍」的差异,但在一个跑几万步、每步都要 AllReduce 的训练里,累积起来就是「训练一天 vs 训练一周」的差距。这就是为什么大模型训练对拓扑极其敏感。
更复杂的并行策略对拓扑的要求更苛刻:
| 并行策略 | 通信特征 | 拓扑要求 |
|---|---|---|
| 数据并行(DP) | AllReduce 梯度 | 越快越好,但相对宽容 |
| 张量并行(TP) | 每层多次 AllReduce | 必须 NVLink,否则极慢 |
| 流水线并行(PP) | 跨 stage 传激活 | 跨节点可接受,但带宽要够 |
第 5 章会深入讲这些并行策略。这里只需记住:张量并行几乎只能在同节点 NVLink 内做,跨节点张量并行会慢到无法接受。这就是为什么调度器必须懂拓扑。
拓扑感知调度(Topology-Aware Scheduling) 的目标是:在调度分布式训练的多个 Pod 时,优先把它们放到通信最快的拓扑位置。它的核心是三步:
每个节点的拓扑信息可以通过几种方式获取:
nvidia-smi topology -m:给出 GPU 之间的互联方式(NVLink、PIX、PHB、SYS 等)。/sys/bus/pci/devices/ 或 lscpu 读取。NVIDIA 的 GPU Operator 会把这些信息以节点标签或资源的形式上报,供调度器查询。典型的 GPU 互联距离编码(NVIDIA 的 topology -m 输出):
| 编码 | 含义 | 通信代价 |
|---|---|---|
| NV | 同 NVLink/NVSwitch | 极低(最优) |
| PIX | 同 PCIe Switch | 低 |
| PHB | 同 PCIe Host Bridge 但不同 Switch | 中 |
| SYS | 跨 NUMA 节点(QPI/UPI) | 高 |
| NODE | 跨节点 | 最高(走 IB/以太网) |
调度器拿到拓扑信息后,要把它转成「打分」。一个简化的打分算法(实际调度器更复杂):
score(node, pod) = Σ w_i * affinity_i 其中 affinity_i 是 pod 对节点上已有/将有的 GPU 的拓扑亲和度: NV → 100 分 PIX → 80 分 PHB → 60 分 SYS → 20 分 NODE → 0 分
权重 w_i 可调,比如张量并行训练把 NV 权重提到极高,强制把 worker 调度到同节点 NVLink 组。
打分后,调度器选分值最高的节点。复杂的场景(如多节点训练)需要协调多个节点的拓扑,这时常配合 Gang Scheduling(见 3.3 节)一起做——把训练的多个 Pod 作为一组同时调度,按整体拓扑最优选择。
K8s 原生调度器对拓扑的支持有限,业界有几种主流方案:
| 方案 | 提供者 | 特点 |
|---|---|---|
| NVIDIA GPU Operator | NVIDIA | 自动上报拓扑标签(如 nvidia.com/gpu.product、NUMA 信息),基础支持 |
| Volcano 拓扑感知 | 华为/CNCF | 在 Volcano 调度器中按拓扑打分,支持训练作业 |
| Kueue + 拓扑 | Kubernetes SIG | Kueue 集成拓扑提示,渐进式增强 |
| Run:AI、Bytedance Volcano fork | 第三方 | 商业或自研增强,支持细粒度拓扑感知 |
| CRD-based 自定义 | 自研 | 通过 Device Plugin + 自定义调度器实现 |
⚠️ 现实挑战:K8s 原生调度器对「拓扑感知」的支持长期是社区痛点。Kubernetes 1.26 引入了 DRA(Dynamic Resource Allocation) 来替代 Device Plugin,目标是更好地表达拓扑与设备组合,但生态成熟仍需时间。生产中多数团队要么用 Volcano/Kueue 内建的拓扑能力,要么自研调度器扩展。
假设要跑一个 8 卡张量并行(TP=8)的大模型训练,通信极度依赖 NVLink。理想的调度流程:
如果调度失败(比如把 worker 0-3 调度到一个节点、4-7 到另一节点),张量并行跨节点 AllReduce 会让训练慢到不可用。这就是为什么拓扑感知对张量并行训练是「必需品」而非「优化项」。
单节点拓扑之外,跨节点的网络拓扑同样关键。多节点分布式训练(数据并行、流水线并行)需要节点间高速网络:
跨节点通信的关键是 RDMA(Remote Direct Memory Access):让一台节点的 GPU 直接读写另一节点 GPU 的显存,绕过 CPU 与操作系统,极大降低延迟。NCCL(NVIDIA 的集合通信库)会自动选择 NVLink/RDMA 的最快路径。
| 网络类型 | 单端口带宽 | 延迟 | 成本 |
|---|---|---|---|
| 千兆以太网 | 1 Gbps | 毫秒级 | 极低 |
| 万兆以太网 | 10 Gbps | 毫秒级 | 低 |
| 100G 以太网 | 100 Gbps | 微秒级 | 中 |
| IB HDR | 200 Gbps | 微秒级 | 高 |
| IB NDR | 400 Gbps | 亚微秒 | 极高 |
💡 判读:跨节点网络是大模型训练的「隐形杀手」。许多团队买了昂贵的 H100,却用 100G 以太网互联,结果 AllReduce 跨节点极慢,整集群吞吐远低于预期。大模型训练几乎必须配 IB 或 RoCE。
拓扑在静态部署时是固定的,但弹性训练(详见 3.4)会让拓扑动态变化——加入的新节点可能与原节点不在同一 IB 子网,跨子网通信会变慢。这要求:
这是当前云原生 AI 的前沿研究方向,业界尚无完美方案,多数团队靠经验规则与手动调优。
下一节《3.3 批处理调度器对比:Volcano、Kueue 与 YuniKorn》将讲清 Gang Scheduling 与作业排队的工程实现。