8 卡 Ascend 910 训练 ResNet-50,同样的 batch size、同样的模型、同样的 NPU,换了一个集合通信算法,吞吐从 1250 images/s 掉到 235 images/s。差了 5.3 倍。

根因不是硬件问题,是 AllReduce 算法选型错了——用 Ring AllReduce 跑 8 卡以上的集群,带宽利用率只有 18%,换成 Mesh AllReduce 直接拉到 92%。

昇腾CANN 的 hccl 是集合通信库,驻留在 CANN 五层架构的第 4 层(昇腾计算执行层)。分布式训练/推理的通信性能,90% 取决于你有没有选对 hccl 的算法。

🏗️ hccl 的三层架构

hccl 的设计理念是算法与链路解耦——算法层不感知底层走的是 HCCS 专用链路还是 RoCE 通用以太链路。这带来一个直接好处:同样的算法代码,换链路不用改。

三层架构:

API 层(对外接口)
 ↓
算法层(Ring / Mesh / RHD)
 ↓
链路层(HCCS / RoCE / PCIe)

API 层:对外接口

提供标准集合通信原语,和 NCCL(NVIDIA 的集合通信库)API 高度兼容。

// hccl 的 AllReduce 接口(类 NCCL 风格)
#include <hccl/hccl.h>

hcclComm_t comm;
hcclCommInitAll(&comm, ndev, devlist);

// 为什么用 hcclAllReduce 而不是自己写通信?
// 因为算法层会自动选最优路径,自己写只能写死一种
hcclAllReduce(sendbuff, recvbuff, count, HCCL_FLOAT32, 
 HCCL_SUM, comm, stream);

支持的原语:

原语 作用 典型场景
AllReduce 多卡梯度聚合 分布式训练梯度同步
Broadcast 单卡广播到多卡 模型参数初始化
AllGather 多卡数据拼接 数据并行输入拼接
ReduceScatter 多卡部分归约 模型并行梯度归约
AlltoAll 全卡点对点交换 MoE 路由、PD 分离

算法层:三种算法,三种取舍

这是 hccl 最核心的部分。同一种原语,不同算法,性能可以差 10 倍

Ring 算法

适合小规模集群(≤8 卡),带宽利用率高,但延迟随卡数线性增长。

原理:卡之间形成逻辑环,数据在环上流动,每轮每个卡发一次、收一次。通信量 = 2(N-1)/N × DataSize,N 是卡数。

// Ring AllReduce 的伪代码逻辑
// 为什么Ring适合小规模?因为环上每跳延迟固定,N小的时候总延迟低
for (int step = 0; step < N-1; step++) {
 int send_to = (rank + 1) % N;
 int recv_from = (rank - 1 + N) % N;
 // 环形流动:每步挪一个chunk
 ExchangeChunk(send_to, recv_from, chunk_id);
}

N>8 以后,环的累计延迟超过带宽优势,性能开始下降。

Mesh 算法

适合大规模集群(>8 卡),利用多维拓扑,延迟低但实现复杂。

原理:卡之间构成多维网格(2D/3D Mesh),通信路径并行度高,延迟随卡数增长远低于 Ring。

// Mesh AllReduce:2D Mesh 上的并行归约
// 为什么Mesh适合大规模?因为X维和Y维可以并行通信
// Ring是串行的,Mesh是并行的
for (int dim = 0; dim < NDIMS; dim++) {
 // 每个维度并行做Reduce
 ParallelReduceAlongDim(rank, dim, mesh_topology);
}

>8 卡以后,Mesh 的吞吐比 Ring 高 3~8 倍。

RHD 算法

针对昇腾专属 HCCS 链路优化,点对点带宽最大化。

HCCS(Huawei Cache Coherent System)是昇腾 NPU 之间的专属高速互联链路,带宽比 RoCE 高 2~4 倍。RHD 算法直接感知 HCCS 的拓扑,选路的时候优先走 HCCS,不走 RoCE。

// RHD 算法:感知 HCCS 拓扑的选路逻辑
// 为什么RHD只适合HCCS链路?因为选路逻辑硬编码了HCCS的拓扑特征
if (IsHCCSAvailable(rank, peer)) {
 // 走HCCS:点对点带宽最大化
 HccsSend(rank, peer, data);
} else {
 // 降级到RoCE
 RoCESend(rank, peer, data);
}

链路层:HCCS / RoCE / PCIe

链路层管的是"数据走哪条物理线路"。

链路类型 带宽 延迟 适用场景
HCCS 392 GB/s(卡间直连) ~1μs Ascend 910 同机 8 卡
RoCE 100~200 GB/s(以太网络) ~5μs 跨机 8 卡以上
PCIe 32 GB/s(CPU-NPU 之间) ~10μs NPU 和 CPU 之间

算法层不感知链路类型——Ring/Mesh/RHD 只管逻辑拓扑,链路层负责把逻辑路径映射到物理线路。

🌲 算法选型决策树

hccl 有自动选型逻辑,但默认规则不一定最优。手动选型用 hcclCommsets 接口:

// 手动指定算法(覆盖自动选型)
hcclCommsets(comm, "AllReduce", "Mesh");
// 为什么手动指定?因为自动选型在边界场景(如8卡)可能选错
// 8卡用HCCS链路,Ring和Mesh性能接近,但Mesh的扩展性更好

决策树:

  1. 卡数 ≤ 8 且用 HCCS 链路 → Ring(延迟最低)
  2. 卡数 > 8 或用 RoCE 链路 → Mesh(扩展性好)
  3. 超大规模(>64 卡) → RHD(感知 HCCS 拓扑,选路最优)
  4. AlltoAll 原语 → 优先 Mesh(利用全互连拓扑)

⚠️ 边界场景警告:8 卡 HCCS 环境,Ring 和 Mesh 性能接近。但如果你计划扩容到 16 卡,直接选 Mesh,避免扩容后性能悬崖。

🔗 hccl 与 hcomm / hixl 的协作关系

hccl 不是孤立的通信库,它和 hcomm、hixl 协同工作。

hcomm:通信基础库,管链路管理和协议抽象。hccl 的链路层调用 hcomm 的接口,hcomm 再往下对接 HCCS / RoCE 驱动。

hixl:单边通信库,支持零拷贝,用于 PD 分离等场景。hccl 的 AlltoAll 原语在 MoE 路由场景下会调用 hixl 做零拷贝优化。

应用层(PyTorch/MindSpore)
 ↓
hccl(集合通信:多对多)
 ↓
hcomm(链路管理、协议抽象) ← hixl(单边通信:点对点、零拷贝)
 ↓
HCCS / RoCE / PCIe(物理链路)

分工明确:hccl 管"多对多"的集合通信,hixl 管"点对点"的单边通信。做 PD 分离(Prefill 和 Decode 分离部署)的时候,hccl 负责 MoE 的 AlltoAll,hixl 负责 KV Cache 的零拷贝传输。

⚙️ 设计理念三原则

hccl 的设计不是随意堆功能,有三个核心原则贯穿始终:

原则一:算法与链路解耦。算法层只管逻辑拓扑,不感知底层是 HCCS 还是 RoCE。换链路不用改算法代码,换算法也不用改链路配置。

原则二:拓扑感知。hccl 初始化的时候自动检测硬件拓扑(HCCS 有几条、RoCE 的带宽是多少、卡之间的跳步是多少),选路的时候用真实拓扑,不是假设拓扑。

原则三:流式执行。通信和计算可以流水并行。hccl 的 API 是异步的,发起通信请求后立刻返回,NPU 在后台跑通信,同时 Cube 单元可以继续算矩阵乘。

import torch
import hccl_torch # PyTorch 的 hccl 后端

# 流式执行:通信和计算并行
# 为什么能并行?因为hccl的API是异步的,发起后立刻返回
# Cube单元继续算下一个矩阵的梯度,同时HCCS链路在传上一个矩阵的梯度
handle = hccl_torch.all_reduce_async(grad_tensor, op='sum')
# 这里可以继续算,不用等通信完成
next_grad = compute_next_batch()
# 等通信完成(如果后面必须要这个结果)
hccl_torch.synchronize(handle)

结尾

hccl 是昇腾CANN 分布式训练/推理的通信 backbone。算法选型错了,8 卡性能可以差 5 倍。卡数 ≤8 用 Ring,>8 用 Mesh,超大规模用 RHD。

仓库地址:https://atomgit.com/cann/hccl

hcomm 仓库:https://atomgit.com/cann/hcomm

hixl 仓库:https://atomgit.com/cann/hixl

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐