
你写了一个 allreduce(grads)背后发生了多少事情hccl 的架构会告诉你答案。框架里调用 allreduce 跟点一份外卖一样简单——一行代码等结果。但如果你是一个在做分布式训练的工程师迟早会有一天发现同样的代码八卡跑得飞起十六卡就开始鬼打墙——吞吐不涨反跌GPU 利用率掉到 60% 以下。查下来十有八九是通信在拖后腿。hccl昇腾集合通信库就是 CANN 生态里专门负责分布式通信的那个模块。它把多张昇腾 NPU 卡之间的数据传输封装成标准的集合通信原语——AllReduce、AllGather、ReduceScatter 等——让框架调用起来像本地操作一样简单。但「封装成简单接口」和「实际处理底层通信」之间有很长的路要走。链接https://atomgit.com/cann/hccl一、hccl 在 CANN 架构中的位置从 CANN 五层架构看hccl 位于第4层执行层与 Runtime、DVPP、Graph Executor 同级。第3层编译层图编译器 / ATC ↓ 编译后的执行图 第4层执行层 ├─ Runtime运行时管理 ├─ Graph Executor图执行器 ├─ HCCL集合通信库 ← 在这里 ├─ DVPP数字视觉预处理 └─ AIPPAI 预处理 ↓ 第5层基础层驱动 / 内存管理hccl 的上游是框架适配器层——PyTorch、MindSpore 等框架通过适配层调用 hccl 的接口。hccl 启动后依赖下层的基础层驱动、内存管理来完成实际的通信操作。二、设计理念两步走的通信抽象hccl 的架构设计围绕一个核心问题展开怎么让上层框架不用关心底层网络拓扑同时又不牺牲性能答案是「两步走」的抽象第一步逻辑通信域Communicator框架层面hccl 暴露一个 Communicator 对象。你只需要告诉它「有多少张卡我怎么访问它们」hccl 会自动把这些卡组织成一个逻辑通信域。框架调用 hcclAllReduce 时只需要指定 Communicator 和要通信的显存地址。第二步物理算法选择hccl 内部会根据卡之间的拓扑关系是否同机、是否同交换机、链路带宽等自动选择最优的通信算法。这不是简单的「同机用 Ring跨机用 Tree」——实际的算法选择远比这个复杂。这种抽象的前半段逻辑通信域保证了接口统一性后半段自动算法选择保证了性能。两者缺一不可。三、核心通信原语hccl 实现了标准集合通信原语每个原语都针对 NPU 显存做了优化AllReduce——所有卡求和每张卡拿到相同的结果。这是分布式训练中最常用的操作梯度同步。hccl 的 AllReduce 实现会根据数据量和卡数自动选择 ReduceScatter AllGather小数据量或直接 Ring AllReduce大数据量。AllGather——每张卡把自己的数据广播给所有卡最后每张卡都拿到全部数据。常用于模型并行中收集各卡的计算结果。ReduceScatter——先求和再按卡切分。这是 AllReduce 的一半操作单独使用时可以减少内存占用。Broadcast——一张卡的数据发给所有其他卡。常用于模型初始化时分发参数。hccl 对这些原语的实现有统一的优化框架通信与计算重叠、多流并发、自适应分段把大数据切成小段并行传输等。四、关键机制拓扑感知的算法选择hccl 的一个核心竞争力是拓扑感知。选对了算法通信效率能差好几倍。举个具体场景你在做数据并行训练八张卡都在一台 Atlas 服务器上。这八张卡通过机内的高速互连HCCS昇腾高速缓存一致性互联两两相连带宽远超机间网络。hccl 检测到「八卡同机」这个拓扑后会选择 Ring 算法——数据在八卡之间沿着环流转每张卡只跟前后的邻居通信总通信量等于 2(N-1)/N × 总数据量。但如果十六张卡分布在两台服务器上各八张情况就变了。两台服务器之间通过 RoCE 网卡连接带宽远低于机内 HCCS。hccl 会选择两级通信算法先在每台服务器内部做 Ring AllReduce充分利用 HCCS 高带宽然后在服务器之间只交换部分聚合数据减少跨机通信量。选择不同算法带来的性能差异很直接——在一些 benchmark 里算法选择最优 vs 最差同一个 AllReduce 操作的延迟可以相差3-5 倍。五、通信与计算重叠当你写下allreduce(grads)时一个隐性的性能杀手是等待——你只在 allreduce 完成了之后才能开始下一轮计算。但如果通信和计算能同时跑你在发数据的同时就能开始做下一层的前向计算。hccl 通过异步通信 多流并发来实现这个重叠// 伪代码通信与计算重叠autostreamhccl_create_stream(device,queue_id);// 在第0层算完之后立即发起梯度 allreduce异步hccl_allreduce_async(layer_0_grad,layer_0_grad,size,dtype,HcclSum,comm,stream);// 不等同时继续算下一层launch_layer_1_forward(data,layer_1_output,stream);// 到这里才同步确保 layer_0 的梯度已经交换完成hccl_stream_sync(stream);launch_layer_1_backward(layer_1_output,layer_0_grad,...);注释解释WHY这里queue_id不是随便填的——不同的流对应 NPU 上不同的硬件队列。层的计算和 allreduce 通信分别占用不同的队列才能真正并行执行。如果共用同一个队列代码逻辑上写的是异步底层硬件执行时还是串行。六、多机通信的可靠性保障多机通信的最大问题是网络不可靠。RoCE 网络偶尔会丢包交换机偶尔会拥塞。hccl 的处理方式是重传 流控重传机制hccl 在 RDMA 层面做 Flow Control检测到丢包后立即触发重传。重传的粒度不是整次 AllReduce 全部重来而是只传丢了的那一个分段。拥塞控制hccl 会检测网络拥塞信号ECN显式拥塞通知在出现拥塞时动态降低发送速率。拥塞解除后自动恢复全速。这些机制对上层框架完全透明。框架调用 allreduce 只会看到「完成」和「失败」中间的重传和拥塞控制全在 hccl 内部消化。七、hccl 对比 NCCL 的几个差异点如果你从 NVIDIA 生态过来hccl 在概念上对标 NCCL但实现上有几个值得注意的差异拓扑粒度NCCL 主要针对 NVLink IB/RoCE 的拓扑做优化hccl 针对 HCCS RoCE 做优化。两者的机内互联特性不同——HCCS 是全互联拓扑每两张卡直接用高速链路连接而 NVLink 在单机八卡场景下存在桥接拓扑。多流支持hccl 对多流并发的支持做得比较深入可以在同一 Communicator 内创建多个流并同时执行不同的通信操作这在 MoE 模型的 Expert Parallelism 场景中非常有用——每个 Expert 的通信可以独立异步进行。八、从哪开始如果你要做昇腾平台上的分布式训练hccl 的价值体现需要一点耐心先用默认配置跑通hccl 的默认算法选择在大多数场景下已经不错了先确认能跑起来。看 Profile 数据用 CANN 自带的 profiling 工具看看通信时间占比。如果超过 20%说明通信是瓶颈值得调。关注拓扑变化加卡的时候通信拓扑变了算法选择可能也跟着变。别假设「加一倍卡加一倍吞吐」——在跨机扩容前先跑一下通信 benchmark 确认线性度。链接https://atomgit.com/cann/hccl