执行摘要
- 一句话:禁用跨节点 TP 的 logits multimem all-gather
- 推荐动作:该 PR 修复了多节点 TP 部署的阻塞性问题,代码简洁,审查充分,建议快速合入。无需精读,但设计模式(在构造函数中禁用跨节点路径)值得在类似场景中复用。
功能与动机
在 4 节点 H20 部署(TP16/TP32)中,启动时 CUDA graph 捕获阶段尝试跨节点创建对称内存,但 torch.distributed._symmetric_memory.rendezvous 失败,导致服务无法就绪。PR body 明确描述该路径在跨节点场景下不可用,需与其他跨节点禁用策略保持一致。
实现拆解
-
在 MultimemAllGatherer.__init__ 中增加跨节点检测:
使用 get_tp_group() 获取 TP 组,通过 in_the_same_node_as(tp_group.cpu_group, source_rank=0) 检查所有 rank 是否在同一节点。若 world_size > 1 且不全在同一节点,则将 self._state 设为 None,从而禁用 multimem 快速路径。该检查仅在 enabled=True(_state 为 _UNINIT)时执行,避免重复导入。
-
回退机制:__call__ 中当 _state 为 None 时,直接调用 tensor_model_parallel_all_gather(NCCL 回退),保持原有逻辑不变。
- 依赖管理:延迟导入
get_tp_group 和 in_the_same_node_as,避免模块加载时的循环依赖。
关键文件:
python/sglang/srt/distributed/device_communicators/triton_symm_mem_ag.py(模块 分布式通信;类别 source;类型 dependency-wiring;符号 MultimemAllGatherer.init, MultimemAllGatherer._build): 核心变更文件,在 MultimemAllGatherer 初始化时增加跨节点 TP 检测逻辑,决定是否禁用 multimem all-gather 快速路径。
关键符号:MultimemAllGatherer.init, in_the_same_node_as
关键源码片段
python/sglang/srt/distributed/device_communicators/triton_symm_mem_ag.py
核心变更文件,在 MultimemAllGatherer 初始化时增加跨节点 TP 检测逻辑,决定是否禁用 multimem all-gather 快速路径。
def __init__(
self,
max_tokens: int,
*,
enabled: bool = True,
skip_entry_sync: bool = False,
):
self._max_tokens = int(max_tokens)
self._skip_entry_sync = skip_entry_sync
# None => always NCCL; _UNINIT => build on first eager call.
self._state = self._UNINIT if enabled else None
# 新增:如果 TP 组跨节点,则立即禁用 multimem all-gather
# 从而避免启动时 rendezvous 失败导致的挂起
if self._state is self._UNINIT:
# Lazy import avoids a module-load dependency on the distributed facade.
from sglang.srt.distributed import get_tp_group
from sglang.srt.distributed.parallel_state import in_the_same_node_as
tp_group = get_tp_group()
if tp_group.world_size > 1 and not all(
in_the_same_node_as(tp_group.cpu_group, source_rank=0)
):
logger.warning(
"multimem all-gather disabled because the TP group spans "
"across nodes."
)
self._state = None # 禁用快速路径,__call__ 将走 NCCL fallback
评论区精华
- 检查位置争议:mmangkad 最初建议将检查移至
_build() 方法中,以守卫真正的 rendezvous 组而非构造函数时的组。但 Fridge003 指出 rendezvous 组与构造函数时的组相同,放在 __init__ 中即可。最终采用 __init__ 方案。
- 测试文件移除:Fridge003 认为无需新增单独测试文件,san-tian 移除了测试。
- 检查位置应放在
_build() 还是 __init__() (design): 采用 __init__ 方案,因为两者组一致且实现更简洁。
- 是否新增测试文件 (testing): 不新增测试,仅修改源码。
风险与影响
- 风险:风险较低。仅当 TP 组跨节点且
multimem all-gather 被启用时才生效,且回退到已广泛使用的 NCCL all-gather 路径。若有单节点跨节点配置混合的情况(罕见),可能无法正确检测,但影响仅为无法享受 multimem 加速。
- 影响:影响范围有限,仅涉及跨节点 TP 组部署场景(如 TP16 跨 2 节点、TP32 跨 4 节点)。修复后服务可正常启动,无性能回归。单节点 TP 组不受影响。
- 风险标记:核心路径变更, 缺少测试覆盖, 跨节点部署
关联脉络
- PR #30088 [DSA] Disable indexer fusion by default to restore DeepSeek-V3.2 accuracy: 同为在初始化时检查跨节点条件并禁用特定功能的模式
- PR #30018 [Fix] Turn off dsa indexer fusion by default: 讨论中提及的类似跨节点禁用策略
参与讨论