GPU 之间怎么「说话」、K8s 里怎么给容器插多块网卡,一次讲透
大模型为什么需要「通信库」?因为模型放不进一张卡。训练一个 70B 模型要几百张 GPU,推理一个长上下文也要 8 卡并行——GPU 与 GPU 之间每走一步都要交换数据:梯度、中间张量、KV Cache。谁来干这件事?就是通信库。
本文把大模型服务里最常见的通信库(NCCL、MPI、GLOO、UCX、NVSHMEM)逐个讲清楚,然后给出一套 Kubernetes 容器多网卡 + NCCL 通信库的实际配置示例,从 YAML 到验证命令全部可抄。
一、先搞清楚:大模型服务到底需要哪些「通信」
1. 三种并行,三种通信模式
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2. 集合通信六种原语
大模型用得最多的是集合通信(Collective Communication):所有 GPU 一起参与的通信模式。
-
Broadcast:一块卡把数据发给所有人 -
Reduce:所有人把数据归约成一个(求和/求平均) -
AllReduce:Reduce + 结果广播给所有人(数据并行每步都要做,最频繁) -
AllGather:每块卡的私有数据收集成完整一份,所有人都有 -
ReduceScatter:归约后按块分散到各卡 -
All-to-All:每块卡给每块卡发不同数据(MoE 路由用)
通信库就是把这些原语实现到极致:该走 NVLink 走 NVLink,该走 RDMA 走 RDMA,CPU 全程靠边站。
二、五大通信库逐个讲
1. NCCL:GPU 集合通信的「事实标准」
NVIDIA Collective Communications Library,英伟达官方出品,训练框架(PyTorch、DeepSeek 全家、Paddle)默认后端。
-
为 GPU 而生:MPI 是「先有 CPU 后有 GPU」,数据经常要在 GPU↔CPU 之间来回拷贝;NCCL 从设计第一天就面向 GPU,通信全程不落 CPU 内存 -
统一硬件路径:机内走 NVLink / PCIe P2P,机间走 InfiniBand / RoCE(GPUDirect RDMA,网卡直接读写显存) -
拓扑感知:NCCL 自动探测 GPU 与网卡之间的 PCIe 拓扑,自建通信图,挑最优路径 -
环与树算法:AllReduce 默认用 Ring(双通道双向)或 Tree,带宽利用率高 -
多网卡自动多通道:一台 8 卡服务器插 8 块 400G 网卡,NCCL 会开多个 channel 把所有网卡并行用满(前文《RoCE 多网卡架构》的实测:8×400G 可达 190GB/s 级聚合带宽) -
配套验证工具: nccl-tests(all_reduce_perf、all_gather_perf)是集群验收的标配
2. MPI:通用并行计算的「老大哥」
Message Passing Interface,HPC 领域三十年标准,代表实现是 OpenMPI、Intel MPI,以及英伟达的 HPC-X。
-
面向通用并行计算:分子动力学、气象、流体……当然也包括大模型 -
早期痛点:MPI 对 GPU 支持是「后来补的」,数据常要经过 CPU 中转 -
现在的解法:CUDA-Aware MPI——OpenMPI/HPC-X 直接接受 GPU 指针,数据不落 CPU 内存,配合 MPI_Allreduce也能跑出接近 NCCL 的性能 -
HPC-X 是 NVIDIA 打包的「全家桶」:UCX(传输层)+ NCCL + SHARP(交换机内归约),NCCL-RDMA 插件就是靠它做跨机 RDMA 的
3. GLOO:PyTorch 自带的「备胎与调试器」
PyTorch 官方内置的分布式后端,与 NCCL 并列可选项。
-
走 TCP socket + 共享内存,也支持 IB(可选),CPU 机器上也能跑 -
启动快、日志友好、依赖少,适合小规模验证和调试 -
性能天花板远低于 NCCL,大规模 GPU 训练几乎没人用 GLOO 打主力——它更像「NCCL 连不上时的保险」和「小模型 + 小 batch 场景的省心选项」
4. UCX:通信库的「框架的框架」
Unified Communication X,定位不是某个应用通信库,而是底层传输统一抽象层:
-
上层:MPI(HPC-X)、OpenSHMEM、GASPI 等都能基于它 -
下层:UCT 传输层把 RDMA(IB/RoCE)、共享内存、TCP 全部统一成一套 API -
好处:一套代码,跨硬件自动选最优传输(有 RDMA 走 RDMA,没有回落共享内存/TCP) -
一句话:你不直接写 UCX,但它可能是你用的 MPI / SHMEM 的发动机
5. NVSHMEM:把「远端内存」变成「自己的内存」
NVIDIA 对 OpenSHMEM 标准的 GPU 实现,单边、细粒度、对称内存通信。
-
对称内存(Symmetric Memory):所有 GPU 拥有同一块虚拟地址空间,本地地址 = 远端地址 -
单边通信:GPU kernel 里的线程直接 put/get远端 GPU 内存,不需要对方 CPU 参与,更不需要显式收发配对 -
细粒度、低延迟、零拷贝,适合图执行器(GraphEngine)、MoE 路由、KV Cache 搬运这类点对点为主的场景 -
与 NCCL 的本质区别:NCCL 是「注册窗口、按需通信」的集合通信;NVSHMEM 是「全局对称堆、统一寻址」的类内存访问。NCCL 通信仍要 CPU 发起(kernel 里靠发信号),NVSHMEM 让 GPU 自己直连 -
注意:NCCL 后来也引入了 Symmetric Memory 特性(NCCL 2.20+),方向趋同
6. 其他你可能会遇到的
-
RCCL:AMD ROCm 的 NCCL 对应物 -
oneCCL:Intel 集合通信库(XPU/CPU) -
MSCCL:微软基于 NCCL 的扩展(SHARP/网络内归约优化) -
Gloo/ray 内部通信、AWS EFA 的 NCCL 插件等
7. 一张表对比
|
|
|
|
|
|
|
|---|---|---|---|---|---|
| NCCL |
|
|
|
|
|
| MPI (HPC-X) |
|
|
|
|
|
| GLOO |
|
|
|
|
|
| UCX |
|
|
|
|
|
| NVSHMEM |
|
|
|
|
|
三、怎么选:一张决策树
-
标准大模型训练/推理,无脑 NCCL(框架默认、生态最全、调优资料最多) -
HPC 传统负载、需要兼容老 MPI 生态 → MPI(CUDA-Aware / HPC-X) -
小模型、CPU 环境、快速验证 → GLOO -
需要一套代码跨多种互连硬件 → 底层让 UCX 干活 -
点对点细粒度通信、想把通信写进 kernel、要自己管内存池 → NVSHMEM -
混合方案最实用:MPI 管 CPU 与任务编排 + NCCL 管 GPU 数据面,这是 OpenMPI + HPC-X 时代的经典组合
四、Kubernetes 多网卡实际配置通信库示例(重点)
1. 为什么 Pod 必须「插多块网卡」
一台 8 卡 GPU 服务器,硬件上通常插了 8 块 200G/400G 网卡,每块网卡和 GPU 一一对等映射(GPU-NIC 亲和,走同一 PCIe root 或 NUMA node)。但默认情况下:
-
K8s Pod 只拿到 1 个 eth0(默认 CNI:Calico/Flannel 等) -
容器里的 NCCL 看到 8 块 GPU、却只有 1 块网卡 → 跨机通信全部挤在一个网卡,8×400G 的硬件只剩 1/8 的带宽
解法就是 Multus(meta-CNI)+ 高性能附加网络:让 Pod 里除了 eth0,还能挂上 8 个 RDMA/RoCE 网卡接口,NCCL 多通道并行。
2. 需要的组件栈
|
|
|
|---|---|
| Multus |
|
| NetworkAttachmentDefinition |
|
| RDMA CNI / SR-IOV CNI |
|
| RDMA shared device plugin / sriov-device-plugin |
|
| NVIDIA Network Operator(可选) |
|
3. 前置条件
-
节点安装 OFED 驱动(Mellanox/NVIDIA), ibv_devinfo能看到网卡 -
物理网卡接入 RoCE 无损网络(交换机开 PFC/ECN,见前文《RoCE 网络架构》) -
K8s 已装好 Multus + RDMA CNI + device plugin
4. 第一步:定义附加网络(NetworkAttachmentDefinition)
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: rdma-net
namespace: default
spec:
config: |
{
"cniVersion": "0.3.1",
"name": "rdma-net",
"type": "rdma",
"pkey": "0xffff",
"linkState": "up",
"mtu": 9000
}
说明:RDMA CNI 把宿主机网卡直接放进 Pod(不占 IP,走 RoCE 的 GID/pkey 寻址),所以通常不需要 IPAM 块;若是 SR-IOV + 独立 IP 的方案,则在 config 里加
ipam或交给sriov-cni的ipam段。
5. 第二步:StatefulSet 声明「多网卡 + RDMA 资源 + NCCL 环境变量」
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: llm-trainer
spec:
serviceName: llm-trainer
replicas: 1
selector:
matchLabels: { app: llm-trainer }
template:
metadata:
labels: { app: llm-trainer }
annotations:
# 挂 8 个 RDMA 附加网络:net1 ~ net8 对应 8 块 RoCE 网卡
k8s.v1.cni.cncf.io/networks: >-
[{"name":"rdma-net","interface":"net1"},
{"name":"rdma-net","interface":"net2"},
{"name":"rdma-net","interface":"net3"},
{"name":"rdma-net","interface":"net4"},
{"name":"rdma-net","interface":"net5"},
{"name":"rdma-net","interface":"net6"},
{"name":"rdma-net","interface":"net7"},
{"name":"rdma-net","interface":"net8"}]
spec:
containers:
- name: trainer
image: nvcr.io/nvidia/pytorch:24.10-py3
resources:
limits:
nvidia.com/gpu: 8
rdma/shared: 8 # RDMA device plugin 暴露的资源,注入 /dev/infiniband
env:
# 控制面/数据面分离:TCP socket 只走默认网卡 eth0
- name: NCCL_SOCKET_IFNAME
value: eth0
# 显式指定全部 8 块 HCA,让 NCCL 开满 channel
- name: NCCL_IB_HCA
value: mlx5_0,mlx5_1,mlx5_2,mlx5_3,mlx5_4,mlx5_5,mlx5_6,mlx5_7
# 保持 RDMA 传输开启(RoCE 场景不能设成 1)
- name: NCCL_IB_DISABLE
value: "0"
- name: NCCL_P2P_LEVEL
value: PXB # 允许同一 PCIe 交换机下的 P2P
- name: NCCL_MIN_NCHANNELS
value: "8"
- name: NCCL_MAX_NCHANNELS
value: "32"
- name: NCCL_DEBUG
value: INFO
# 无损网络参数,RoCE 建议开启超时重试
- name: NCCL_IB_TIMEOUT
value: "22"
- name: NCCL_IB_RETRY_CNT
value: "7"
command: ["/bin/bash", "-c"]
args:
- |
torchrun --nnodes=8 --nproc-per-node=8 --rdzv-endpoint=trainer-0 \
train.py
要点拆解:
-
**注解 k8s.v1.cni.cncf.io/networks**:Multus 的核心入口,每个附加网络对应 Pod 里的一块网卡(net1~net8)。8 卡 8 网卡,正好对上 GPU-NIC 对等映射 -
**资源 rdma/shared**:由 RDMA shared device plugin 提供,声明后 K8s 把宿主机的 /dev/infiniband 设备注入容器 -
NCCL 环境变量全部下放到容器:多网卡场景里这是通信库配置的灵魂
6. 第三步:NCCL 关键环境变量速查
|
|
|
|
|---|---|---|
NCCL_SOCKET_IFNAME |
|
eth0
|
NCCL_IB_HCA |
mlx5_* 通配)
|
|
NCCL_IB_DISABLE |
|
0
|
NCCL_P2P_LEVEL |
|
|
NCCL_MIN/MAX_NCHANNELS |
|
|
NCCL_DEBUG |
|
|
NCCL_IB_TIMEOUT
NCCL_IB_RETRY_CNT
|
|
|
7. 第四步:进容器验证(能不能跑满,一测便知)
# 1) 看 RDMA 设备是否注入
ibv_devinfo -d mlx5_0 | grep -E "state|port"
# 2) 看多网卡是否都在
ip addr show | grep -E "^[0-9]+:"
# 3) 通信库压测(8 卡单机 or 多机)
mpirun -np 8 all_reduce_perf -b 128M -e 8G -f 2 -g 8
# 或单机版
all_reduce_perf -b 128M -e 8G -f 2 -g 8
# 4) 看 NCCL 到底用了哪些网卡
# 启动时加 NCCL_DEBUG=INFO,关注日志里的 NET/IB 行:
# "NET/IB : 8 HCA(s) selected" → 8 块网卡全部参与,达标
诊断口诀:看到 NCCL_DEBUG=INFO 里 NET/IB : N HCA(s) selected,N 等于物理网卡数,就算成功;如果只显示 1 块,多半是 NCCL_IB_HCA 没放开或设备注入不全。
五、常见坑与排查
-
容器里看不到 /dev/infiniband:device plugin 没装或没声明 rdma/shared资源;确认节点kubectl describe node | grep rdma -
NCCL 走 TCP 不走 RDMA: NCCL_IB_DISABLE=0、HCA 可见、RoCE 交换机无损配置齐全(PFC/ECN),三者缺一不可 -
多网卡但带宽只有一块卡的水平: NCCL_IB_HCA被限制、NCCL_MAX_NCHANNELS太小,或 Multus 只挂了一块附加网卡 -
网卡名漂移(eth0↔ens3):用 NCCL_SOCKET_IFNAME固定,别依赖动态名 -
跨机性能骤降:检查 GPU-NIC 是否跨 NUMA/PCIe root,对等映射错位会损失 30%+ 带宽 -
容器启动报 permission:RDMA 设备注入 + 必要的 privileged/CAP 配置,用 Network Operator 统一管理 -
NCCL 版本太老:多 HCA、Symmetric Memory 等特性需要较新版本,训练镜像尽量用 NGC 基础镜像(自带调优后的 NCCL)
六、落地设计要点(八条)
-
先验收再扩容:新集群必须跑 nccl-tests all_reduce_perf全量验收,记录每机带宽基线 -
网卡与 GPU 对等映射:部署前核对 PCIe 拓扑,确保 8 卡对 8 网卡、NUMA 亲和,错位补不回来 -
控制面与数据面分离:管理流量走 eth0,训练流量走 RDMA 多网卡, NCCL_SOCKET_IFNAME指对 -
环境变量写进镜像/StatefulSet:别靠人肉 export,配置即代码,NCCL_DEBUG 先用 INFO 灰度 -
无损网络是前提:RoCE 不配 PFC/ECN,带宽越高丢包越惨,NCCL 重试参数兜底(TIMEOUT=22) -
多网卡要测聚合带宽:单卡打满不代表 8 卡打满, all_reduce_perf -g 8看的是多通道聚合 -
镜像选 NGC 基础镜像:自带调优 NCCL + 驱动兼容性验证,省掉一半玄学问题 -
监控与告警:NCCL 报错(超时/断连)直接挂到训练告警,跑大任务前先跑 10 分钟小规模验证
七、写在最后
通信库是大模型分布式系统的「隐形基础设施」:你看到的 90% 训练卡在「通信瓶颈」,答案往往不在算力,而在网卡有没有被 NCCL 用满。选型记住一句话:训练/推理主力 NCCL,HPC 兼容 MPI,底层传输 UCX,细粒度点对点 NVSHMEM,调试备胎 GLOO;落地记住一句话:K8s 里用 Multus 插网卡、device plugin 注入设备、NCCL 环境变量把多通道开满——三件事做对,8×400G 的硬件才真正属于你的模型。
关于向量云:大模型部署,把基础设施的复杂性留给我们
通信库调优、多网卡配置、集群验收,都是持续的基础设施工程。向量云(南京)科技有限公司依托字节跳动火山方舟官方授权,专注大模型应用落地:
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
接入方式:注册后获取官方 API Key,把 base_url 指向向量云接入点即可直接调用火山方舟官方模型。
常见问题(FAQ)
Q1. 大模型服务里的「通信库」是什么?A. 通信库是负责 GPU 之间、机器之间数据交换的软件层。大模型分布式训练/推理中,梯度同步(AllReduce)、张量合并、KV Cache 搬运都要跨卡跨机,通信库把这些通信原语高效实现(走 NVLink、RDMA,绕开 CPU)。最常用的就是 NCCL,此外还有 MPI、GLOO、UCX、NVSHMEM 等。
Q2. NCCL 和 MPI 有什么区别?A. NCCL 是英伟达面向 GPU 设计的集合通信库,全程不落 CPU 内存,直接走 NVLink/PCIe P2P 和 RDMA,是大模型训练的事实标准;MPI 是通用并行计算标准,出身 CPU 生态,CUDA-Aware MPI(如 HPC-X)才支持 GPU 缓冲直通。HPC 传统负载用 MPI 多,大模型训练用 NCCL 多。
Q3. GLOO 什么时候用?A. GLOO 是 PyTorch 内置的轻量后端,走 TCP/共享内存,启动快、调试友好。适合小模型、CPU 环境、快速验证,以及 NCCL 连不上时的兜底。大规模 GPU 训练性能拼不过 NCCL,不适合打主力。
Q4. NVSHMEM 和 NCCL 的本质差别是什么?A. NCCL 是「注册窗口、按需通信」的集合通信,通信仍由 CPU 发起;NVSHMEM 是「全局对称堆、统一寻址」——所有 GPU 共享同一虚拟地址空间,kernel 内线程可以直接 put/get 远端 GPU 内存,单边、细粒度、零拷贝,适合 MoE 路由、KV Cache 搬运这类点对点场景。
Q5. Kubernetes 里 Pod 为什么需要多网卡?怎么配?A. 默认 Pod 只有一个 eth0(管理/默认网络),而 8 卡服务器通常有 8 块 400G 网卡且与 GPU 对等映射,只挂一块网卡等于浪费 7/8 带宽。用 Multus(meta-CNI)通过 k8s.v1.cni.cncf.io/networks 注解把附加网络(RDMA/SR-IOV)挂进 Pod,再配 RDMA device plugin 注入 /dev/infiniband 资源即可。
Q6. 多网卡场景要配哪些 NCCL 环境变量?A. 核心四件套:NCCL_SOCKET_IFNAME(控制面网卡,如 eth0)、NCCL_IB_HCA(全部 RDMA 网卡列表)、NCCL_IB_DISABLE=0(保持 RDMA)、NCCL_DEBUG(排查用 INFO)。加分项:NCCL_P2P_LEVEL(机内 P2P 拓扑级别)、NCCL_MIN/MAX_NCHANNELS(通道数)、NCCL_IB_TIMEOUT/RETRY_CNT(RoCE 重试)。
Q7. 容器里 NCCL 走不通 RDMA 怎么排查?A. 三步:① 容器内 ibv_devinfo 确认 /dev/infiniband 注入;② 确认 NCCL_IB_DISABLE=0 且 NCCL_IB_HCA 指定正确网卡;③ 开 NCCL_DEBUG=INFO 看日志中 NET/IB : N HCA(s) selected——N 应等于物理网卡数。还有前置条件:RoCE 交换机必须配好无损网络(PFC/ECN)。

