分布式通信原语

分布式集合通信原语详解

引言

在分布式系统和并行计算中,多个节点(进程、线程、GPU)协同完成任务时,必然涉及"一对多""多对一""多对多"的数据交换。这些操作被抽象为集合通信原语(Collective Communication Primitives),是 MPI、NCCL、Gloo、Horovod 等通信库的基石,也是分布式机器学习与科学计算的核心。

理解每种原语的原理、使用场景、通信量,能帮助我们在系统设计时:

  • 选择合适的算法实现(Ring / Tree / Butterfly / Rabenseifner 等);
  • 估算网络瓶颈与扩展性;
  • 排查分布式训练中的性能问题。

本文系统梳理经典原语:Broadcast、Scatter、Gather、All-Gather、Reduce、All-Reduce、Reduce-Scatter、All-to-All、Scan 和 Barrier


符号约定

为方便后文比较,先统一符号:

符号 含义
p 参与节点数(ranks)
n 每个节点持有的数据量(字节,本文取"输入时每节点数据量"为基准)
α 消息启动延迟(latency)
β 单位数据传输时间(bandwidth inverse)

通信成本常用 Hockney 模型 :发送大小为 m 的消息耗时 ≈ α + m·β

下文"通信量"同时给出:

  1. 每节点发送字节数(决定最慢节点的瓶颈)
  2. 全网总流量(决定网络压力)
  3. α-β 时间估算(粗略但能反映扩展性)

一、Broadcast(广播)

原理

根节点(root)将同一份长度为 n 的数据发送给其余 p-1 个节点。结束后,每个节点都持有这份数据。

常见算法:

复制代码
朴素(朴素线性)
  root → node1 → node2 → ... → node(p-1)
  共 p-1 次串行发送,root 串行瓶颈严重

递归倍增 / Binomial Tree
            root
           /    \
         n1      n2
        / \     / \
      n3  n4  n5   n6
  每一层并发广播,共 ⌈log₂ p⌉ 步
  每个节点最多接收并转发 n 一次

Binomial Tree 是 MPI/NCCL 中最常见的实现。

使用场景

  • 模型参数、超参数分发到所有 worker;
  • 初始化阶段把同一份配置复制到每个 rank;
  • 一致性状态机中的全局状态分发。

通信量

指标 朴素 Binomial Tree
每节点发送 root: (p-1)·n,其他: 0 至多 n
全网总流量 (p-1)·n (p-1)·n
α-β 时间 (p-1)·α + (p-1)·n·β ⌈log₂ p⌉·(α + n·β)

关键点 :Tree 算法的并行度高,总流量相同但延迟随 log p 增长,适合小消息;朴素串行实现适合极大消息但节点很少的场景。


二、Scatter(分散)

原理

根节点持有长度为 p·n 的数据,逻辑切成 p 份;通信结束后,节点 i 收到第 i 份(长度为 n)。

与 Broadcast 的区别:Broadcast 每节点得到完整数据;Scatter 每节点得到不同片段。

复制代码
       root
      [a0|a1|a2|a3]   ← p·n 总长
       ↓   ↓   ↓   ↓
       n0  n1  n2  n3    ← 每节点拿到自己那份

使用场景

  • 大矩阵按行分片到不同 worker(矩阵乘法的前置步骤);
  • 数据并行中的样本划分;
  • 任务分发:每 worker 领到不同的子任务。

通信量

指标
每节点 root 发送 (p-1)·n;其他节点接收 n
全网总流量 (p-1)·n
α-β 时间 ⌈log₂ p⌉·(α + n·β)(树形实现)

三、Gather(收集)

原理

每个节点持有长度 n 的数据,根节点最终得到按 rank 顺序拼接的 p·n 数据。

是 Scatter 的逆操作。

使用场景

  • 收集所有 worker 的局部结果到 master 做汇总;
  • 把分散计算的指标收回到中心节点;
  • 与 Scatter 配合做矩阵分块计算。

通信量

指标
每节点 非 root 发送 n;root 接收 (p-1)·n
全网总流量 (p-1)·n
α-β 时间 ⌈log₂ p⌉·(α + n·β)

四、All-Gather(全收集)

原理

每个节点持有长度 n 的数据;通信结束后,每个节点都拥有完整拼接的 p·n 数据

常见算法:

复制代码
Ring All-Gather(p=4 示意)
  step 0:  [a][b][c][d]   ← 初始状态
  step 1:  [a|b][b|c][c|d][d|a]   ← 每节点收下一跳数据
  step 2:  [a|b|c][b|c|d][c|d|a][d|a|b]
  step 3:  [a|b|c|d][b|c|d|a][c|d|a|b][d|a|b|c]
  共 p-1=3 步

Bruck All-Gather(对数步)
  step 1: 每节点发给 (i+1) mod p
  step 2: 每节点发给 (i+2) mod p   ← 携带已收数据
  ...
  step k: 每节点发给 (i+2^(k-1)) mod p
  共 ⌈log₂ p⌉ 步,但消息大小指数增长

使用场景

  • 分布式训练中先 All-Gather 收集所有 worker 的局部张量,再做 Reduce;
  • 各节点需要看到全局信息(如全局指标汇总);
  • 矩阵分块计算后做拼合(gemm 之后需要把分片拼回)。

通信量

指标 Ring Bruck
每节点 (p-1)·n 发送 + (p-1)·n 接收 每步消息倍增,总和近似 (log p)·n·p
全网总流量 p·(p-1)·n p·(log p)·n·(p+1)/2
α-β 时间 (p-1)·α + (p-1)·n·β log p·α + (log p)·n·β·(p+1)/2

Ring 适合大消息,Bruck 适合小消息(步数少)。


五、Reduce(归约)

原理

每个节点持有长度 n 的数据,根节点应用结合性算子 (SUM、MAX、MIN、PROD、LOR、LAND、BXOR 等),最终得到长度 n 的归约结果。

算子必须满足结合律(最好还满足交换律),以便分布式执行。

使用场景

  • 各节点计算局部梯度/损失,在 root 汇总为全局值;
  • 全局统计量(所有节点的最大值、总和、均值);
  • 把分布式计算结果汇总到一台机器落盘。

通信量

指标
每节点 非 root 发送 n;root 接收并计算 (p-1)·n
全网总流量 (p-1)·n
α-β 时间 ⌈log₂ p⌉·(α + n·β)(树形 + 算子在树上合并)

六、All-Reduce(全归约)⭐

原理

每个节点持有长度 n 的数据;通信结束后,每个节点都得到归约结果 (长度仍为 n)。

这是分布式深度学习训练里使用频率最高的原语------梯度同步本质上就是一次 All-Reduce。

常见算法:

朴素实现

Reduce 到 root + Broadcast,root 是瓶颈。

Ring All-Reduce ⭐

分两步:

复制代码
第 1 步:Reduce-Scatter
  把数据切成 p 段,每段沿环累加 p-1 步
  每节点最终持有归约后的 1/p 片段

第 2 步:All-Gather
  每节点把它持有的 1/p 片段广播给其他节点
  经过 p-1 步后每节点收集全

Ring All-Reduce(p=4 示意,"S"代表 Reduce-Scatter,"G"代表 All-Gather)

   S1   S2   S3   G1   G2   G3
  ─┼────┼────┼────┼────┼────┼────► 时间
   a    b    c    d
   ↓    ↓    ↓    ↓
  每个 chunk 经 3 次累加,每个节点最终持有 1 个 chunk 的归约结果
  然后 All-Gather 把 1 个 chunk 广播给其他节点

核心优势 :每节点总通信量 2·(p-1)·n/p ≈ 2n与节点数 p 几乎无关

Tree All-Reduce

递归倍增树,每步 n 数据并行累加。

Double Binary Tree (Rabenseifner)

两棵二叉树组合,构造一个 log p 步算法,同时通信量低。

使用场景

  • 分布式深度学习训练的梯度同步(PyTorch DDP、Horovod、DeepSpeed 的核心);
  • 全局参数服务器中的聚合步骤;
  • 所有节点需要一致的全局聚合值(如全局平均 reward、loss);
  • 规约后做下一步决策(All-Reduce 出的 logits、概率)。

通信量

算法 每节点 全网总流量 α-β 时间
朴素(Reduce+Bcast) ~p·n ~2p·n O(p·α + p·n·β)
Ring 2·(p-1)·n/p ≈ 2n 2·(p-1)·n 2·(p-1)·α + 2n·β
Tree ~2n·log p ~2p·n·log p O(log p·(α + n·β))
Double Binary Tree ~2n ~2p·n O(log p·α + n·β)

关键洞察 :Ring All-Reduce 的每节点通信量几乎与 p 无关------这正是分布式训练能扩展到上千 GPU 的核心原因。NCCL 默认对大消息使用 Ring,对小消息使用 Tree。


七、Reduce-Scatter(归约-分散)

原理

每个节点持有长度 p·n 的数据(切分为 p 段);按段做归约后,节点 i 持有第 i 段(长度 n)。

可以理解为:Reduce 输出被 Scatter 到不同节点

复制代码
输入(每节点 p·n)
  node0: [a0|a1|a2|a3]
  node1: [b0|b1|b2|b3]
  node2: [c0|c1|c2|c3]
  node3: [d0|d1|d2|d3]

输出(每节点 n)
  node0: a0⊕b0⊕c0⊕d0
  node1: a1⊕b1⊕c1⊕d1
  node2: a2⊕b2⊕c2⊕d2
  node3: a3⊕b3⊕c3⊕d3

使用场景

  • Ring All-Reduce 的第一步;
  • 把归约结果直接分布到不同 worker 处理(不需要后续 All-Gather);
  • 分布式矩阵运算中的部分结果归约。

通信量

指标 Ring
每节点 (p-1)·n/p 发送 + (p-1)·n/p 接收
全网总流量 (p-1)·n
α-β 时间 (p-1)·α + (p-1)·n·β/p

八、All-to-All(全局转置)

原理

每个节点持有 p 段数据(总长 p·n),第 i 段要发给节点 i;通信结束后,每个节点收到来自所有节点的各 1 段(拼成长度 p·n)。

本质上是 p × p 的转置操作。

复制代码
All-to-All(p=4 示意)
输入:
  node0: [a0→n0 | a1→n1 | a2→n2 | a3→n3]
  node1: [b0→n0 | b1→n1 | b2→n2 | b3→n3]
  node2: [c0→n0 | c1→n1 | c2→n2 | c3→n3]
  node3: [d0→n0 | d1→n1 | d2→n2 | d3→n3]

输出:
  node0: [a0→n0 | b0→n0 | c0→n0 | d0→n0]
  node1: [a1→n1 | b1→n1 | c1→n1 | d1→n1]
  ...

使用场景

  • 矩阵转置 :分布式 A^T
  • MoE(混合专家)路由:把 token 分发给对应的专家 GPU;
  • 推荐系统:跨分片的 embedding 查询结果聚合;
  • 数据重分布:把数据按新的 rank 顺序重排。

通信量

指标 Ring/Spread Bruck
每节点 发送 p·npn 大小消息) 每步数据倍增
全网总流量 p²·n p²·n/2
α-β 时间 p·α + p·n·β(顺序发送) 或 log p·α + p·n·β(优化) log p·(α + n·β)

All-to-All 是通信量最重的原语,p 增大时扩展性较差------这也是 MoE 推理中专家数量受限的重要原因。


九、Scan / Prefix Sum(前缀扫描)

原理

每个节点持有长度 n 的元素序列(或长度 n 的单元素),应用结合性算子后,节点 i 得到前 i+1(或前 i)个节点数据的归约结果

复制代码
Inclusive Scan(p=4,SUM)
  输入:  a,  b,  c,  d
  输出:  a,  a+b,  a+b+c,  a+b+c+d

Exclusive Scan
  输出:  0,  a,  a+b,  a+b+c

常见算法:

复制代码
朴素:链式串行
  node0 → node1 → node2 → node3
  O(p) 步

Blelloch Scan(双调)
  Up-sweep(归约树)+ Down-sweep(前缀分发)
  O(log p) 步

使用场景

  • 分布式前缀和:在多节点上做累计分布、排序、负载均衡;
  • 稀疏矩阵 CSC 格式构建中的索引累加;
  • 流式/流水线并行中的位置索引分配;
  • 编译器中的数据流分析。

通信量

指标 Blelloch
每节点 n·log p 量级
α-β 时间 log p·(α + n·β)

十、Barrier(同步屏障)

原理

无数据移动。所有节点必须到达同一同步点后才能继续。常作为其他集合通信的前置隐式同步。

实现方式:

复制代码
集中式:所有节点发心跳到某个协调者,协调者收到全部后通知大家
对等式:每对节点互相握手确认
dissemination barrier:log p 步对数算法

使用场景

  • 阶段边界:确保所有节点完成当前阶段才进入下一阶段;
  • 分布式训练中区分 iteration/epoch;
  • 调试同步问题(人为插入 barrier 排查 race condition)。

通信量

  • 数据移动:0
  • α-β 时间:集中式 O(log p·α),对等式 O(p·α)

十一、对比总结

原语 输入 / 节点 输出 / 节点 每节点通信量 主要场景
Broadcast root: n 每节点: n Tree: n;朴素: (p-1)·n 参数分发
Scatter root: p·n 每节点: n (p-1)·n(root) 数据切分
Gather 每节点: n root: p·n (p-1)·n(非 root 发) 结果汇总
All-Gather 每节点: n 每节点: p·n Ring: (p-1)·n 全局可见
Reduce 每节点: n root: n (p-1)·n 局部聚
All-Reduce 每节点: n 每节点: n Ring: ~2n 梯度同步
Reduce-Scatter 每节点: p·n 每节点: n Ring: (p-1)·n/p All-Reduce 子步
All-to-All 每节点: p·n 每节点: p·n p·n 转置 / MoE
Scan 每节点: n 每节点: prefix n·log p 前缀和
Barrier --- --- 0 同步

十二、实现算法一览

算法 适用原语 每节点通信量 α-β 时间
Naive / Linear 几乎所有 O(p·n) O(p·α + p·n·β)
Ring All-Gather, All-Reduce O(n)(不随 p 增长) O(p·α + n·β)
Binomial Tree Broadcast, Reduce O(n·log p) O(log p·(α + n·β))
Bruck All-Gather O(n·log p) O(log p·(α + n·β))
Double Binary Tree (Rabenseifner) All-Reduce O(n) O(log p·α + n·β)
Blelloch Scan O(n·log p) O(log p·(α + n·β))
Butterfly All-Reduce O(n·log p) O(log p·(α + n·β))

算法选择经验法则

  • 大消息 + 多节点 → Ring:通信量恒定,带宽主导;
  • 小消息 + 多节点 → Tree:步数少,延迟主导;
  • 梯度同步几乎总是 Ring :通信量与 p 无关,是分布式训练能扩展的根本;
  • 消息极小(如同步信号) → Bruck / Tree :避免 Ring 的 O(p) 延迟;
  • GPU 集合通信 → 拓扑感知:NCCL 会根据 NVLink / PCIe / IB 自动选 Ring 或 Tree。

十三、工程实践要点

1. 让通信和计算流水线化

把集合通信与前向/反向计算 overlap 是性能关键:

  • PyTorch DDP 的 gradient bucketing:梯度按 bucket 触发 All-Reduce,反向传播时提前触发,减少尾部等待;
  • ZeRO / FSDP 的 预取 + 通信窗口
  • 手动实现 comm_stream 与计算 stream 分离(CUDA)。

2. 选择合适的消息大小

  • NCCL / MPI 的集合通信对小消息和大消息会切换算法;
  • 把多个小张量合并成一次大集合通信(concat 后再 All-Reduce),避免反复启动;
  • 但消息过大时会受网络拥塞影响,需要权衡。

3. 拓扑感知与 placement

  • GPU 之间的 NVLink、PCIe 拓扑决定集合通信带宽;
  • NCCL_IB_HCANCCL_SOCKET_IFNAME 等环境变量可调网络设备;
  • 节点内 NVLink + 节点间 IB 是常见异构拓扑,NCCL 会自动分层调度。

4. 异步与 group 语义

  • NCCL 的 ncclGroupStart/End 可以把多次集合通信合并为一个提交,避免频繁同步;
  • PyTorch DDP 用 process_group 隔离不同并行策略(数据并行、专家并行);
  • MPI 的 MPI_Win + RMA 在某些场景下比集合通信更高效。

5. 容错与重试

  • 大规模训练中节点故障不可避免,需要 All-Reduce 容错实现(如 NCCL 的 fault-tolerant 模式、Elastic All-Reduce);
  • 集合通信 + Checkpoint 是工业级系统的标配。

十四、常见框架对照

框架 适用 特点
MPI (OpenMPI / MPICH) HPC、跨语言 最完整、跨语言事实标准
NCCL (NVIDIA) NVIDIA GPU + NVLink/IB 针对 GPU 优化,是 PyTorch DDP 的默认后端之一
Gloo (Meta) CPU/GPU 通用 简单可移植,PyTorch DDP 备选后端
OneCCL (Intel) Intel CPU/GPU Intel 生态深度优化
Horovod (Uber) 深度学习 基于 MPI/NCCL,提供更易用 API
ACCL / HCCL 自研 阿里 / 华为自研集合通信库,针对自研网卡优化

十五、小结

  • Broadcast / Scatter / Gather:基础分发与收集;
  • All-Gather / Reduce-Scatter:数据重分布的两种基本动作;
  • All-Reduce ⭐:分布式训练的灵魂,几乎所有参数同步都靠它;
  • All-to-All:通信量最重,但 MoE / 转置场景不可替代;
  • Scan:并行算法里的关键工具;
  • Barrier:纯同步原语,是其他集合通信的"伴生"。

理解这些原语的原理(看流程图)、通信量(看公式)、使用场景(看业务),就能在设计分布式系统时做出合理选择,在排查性能问题时迅速定位瓶颈。


相关推荐
实战派K8S&DB1 小时前
GaussDB 高可用演进:从流复制到 DCF 分布式共识
分布式·gaussdb
写后端的胖头鱼2 小时前
【高频面试题】分布式锁在项目中的应用
java·分布式·后端·分布式锁·高频面试题
clz13145213 小时前
Kafka 日消 10 亿场景:用 ConcurrentLinkedQueue 实现高性能批量消费缓冲
分布式·kafka·linq
隐擎fox13 小时前
高性能网络爬虫架构设计:基于 Python 的长连接复用与分布式会话池调度实践
分布式·python·网络协议·tcp/ip·高并发·网络爬虫、
闲云自留地20 小时前
云平台存储管理员:Cinder 创建挂载卷 + Swift 分布式存储原理
分布式·wpf·swift
橙子圆1231 天前
RabbitMQ知识1
分布式·rabbitmq
clz13145211 天前
风险特征系统 EPC 子系统:基于 Kafka 数据源与数据集配置的 Flink 指标清洗加工
分布式·flink·kafka
海上小飞龙1 天前
分布式和微服务,一次讲清
分布式·微服务·架构