开发者
下载
多通信域并发下发导致 HCCL 通信死锁问题分析与解决方案

多通信域并发下发导致 HCCL 通信死锁问题分析与解决方案

昇腾CANN

Released: 2026/06/04

背景概述

在基于 CANN(Compute Architecture for Neural Networks)框架的高性能推理场景中,多通信域(Multi-Communication Domain)机制被广泛用于优化大规模模型并行训练与推理任务的通信效率。特别是在使用 Omni Infer 框架加速大模型推理时,开发者常需通过自定义通信调度策略(如 omni-placement)对不同通信域进行精细化控制。

本文针对在启用 TASK_QUEUE_ENABLE=2 流水优化后,出现的 HCCL 通信超时问题展开深入分析。该问题表现为:在四机部署环境下,部分设备在执行 AllGather、ReduceScatter 等通信算子时发生流同步失败,最终导致整个通信流程卡死。通过日志、堆栈分析与通信时序建模,定位到根本原因为多通信域算子在同进程、同 context 下未保证串行下发,引发设备级死锁。本文将从现象、分析、根因到解决方案进行系统性阐述。


问题现象

在开启 TASK_QUEUE_ENABLE=2 的流水优化模式下,使用 Omni Infer 框架运行大模型推理任务时,部分节点(如 device 5)出现 HCCL 通信超时,日志中报错如下:

E39999 aicpu exceptionsynchronize failed: stream synchronization failed

进一步查看 debug/device 目录下的日志,发现仅 device 5 存在异常,其余设备正常。但通过分析通信等待链,发现多个设备间存在相互等待关系,最终形成闭环死锁。


故障排查与分析

1. 通信等待链路溯源

以 device 0 为例,搜索 local_rank 信息,定位到通信域 enp23s0f3_64000_0_1769152667397117,发现 rank 0 的 ringAllGather 算子正在等待 rank 8,而 rank 8 又在等待 rank 1。

继续分析 rank 1,发现其所在设备上存在其他通信域的未完成任务,正在等待 rank 11 的通信完成。

2. 通信域下发不一致问题

搜索 rank 11 的日志,未在 group_name_3 通信域中发现 device 11 的报错,但通过 identifier[192.168.0.17%enp23s0f3_64000_0_1769152667397117] 搜索确认,rank 11 确实存在于该通信域。

进一步排查发现:

device 0 上未下发 reducescatter 算子;

device 11 上未下发对应通信域的通信算子。

这表明:同一通信域内的算子在不同设备上下发不一致,导致部分 rank 持续等待,最终引发超时。

注:在单机 16 卡场景下,通常可默认 rank 与 device 一一对应,但当存在多通信域并发下发时,此假设不再成立。

3. 通信域调用来源差异

进一步分析业务代码,发现:

enp23s0f3 命名的通信域由 omni-placement 模块通过 C++ 接口发起;

group_name_3 通信域由 vLLM 框架通过 PTA 的 Python 接口发起。

两者虽共用同一进程与 HCCL Context,但调用路径不同,缺乏统一的下发顺序控制。


4. 流水优化引发的设备同步阻塞

开启 TASK_QUEUE_ENABLE=2 后,workspace 显存申请操作被移至二级流水线线程中。当显存不足时,会触发 device synchronization 等待其他线程释放资源。

通过 pstack 工具采集卡死时刻的堆栈,发现:

device 0 在等待 device 同步;

由于 omni-placement 与 vLLM 共享同一进程和 context,device 0 需等待 omni-placement 完成其通信任务;

但 omni-placement 本身又在等待 group_name_3 通信域的算子下发,形成闭环依赖。


5. 死锁形成时序分析

通过梳理通信算子下发时序,发现以下四个等待节点构成死锁环:

  1. device 11 的通信域 2 的 send/recv 算子,等待通信域 1 的 kernel 占用 AICPU;
  2. device 11 的通信域 1 的 reduceScatter 算子,等待 device 14 的通信域 1 算子通信;
  3. device 14 的通信域 1 的 reduceScatter 算子未下发,等待通信域 2 的 send/recv 完成;
  4. device 14 的通信域 2 的 send/recv 算子,等待 device 11 的 send/recv 完成。

该闭环结构在多线程、多通信域并发下发且缺乏保序机制时极易触发。


问题根因

在多通信域并发场景下,同一进程、同一 HCCL Context 内的不同通信模块(如 omni-placement 与 vLLM)未对通信算子的下发顺序进行统一管理,导致算子在各设备上的下发时序不一致。

当启用 TASK_QUEUE_ENABLE=2 后,显存申请引入 device 同步机制,进一步放大了并发下发带来的依赖不确定性。最终在通信算子下发乱序、设备同步等待与通信域间依赖交织下,形成闭环死锁。


解决措施

为避免此类问题,需在开发中严格遵守以下原则:

✅ 所有通信域下的通信算子,在每个 Device 上必须保证串行下发。

具体实施建议如下:

在多通信域场景中,统一使用一个调度器管理所有通信算子的下发;

避免跨模块(如 C++ 与 Python)独立调用 HCCL 接口;

若必须使用多线程/多模块通信,应通过显式同步机制(如 barrier、event)确保下发顺序;

在启用流水优化时,对显存申请与通信下发进行资源隔离,避免因同步阻塞引发死锁。


建议与总结

  1. 通信域管理规范:参考 CANN 官方文档 - 通信域管理,确保多通信域使用中遵循统一调度策略。
  2. 多线程通信约束:当使用 COMM_MULTI_THREAD 模式时,必须由用户显式管理通信域(hcclComm),并保证算子下发的串行性。
  3. 调试建议:启用 HCCL_ENTRY_LOG_ENABLE=1 查看算子下发日志;使用 pstack 或 gdb 采集卡死时刻堆栈;通过 rankTableFile 验证通信拓扑配置正确性。
  4. 最佳实践:在高并发通信场景中,优先采用统一通信调度器,避免多路径并发下发,从根本上杜绝因下发乱序引发的死锁风险。
本文所述问题源于多通信域并发下发与设备同步机制的耦合,核心在于“保序”原则的缺失。通过统一调度、串行下发与资源隔离,可有效规避类似问题,保障大规模推理任务的稳定性与性能。

This Page