🧠 背景概述
- 目标:在
init_process_group中实现跨进程注册、排序及 barrier 同步,为 NCCL/Gloo 通信组构建创建一致上下文。 - 时序:所有
set/get/wait操作均发生在 NCCL 通信初始化之前(即 rendezvous 阶段)。 - 机制:socket 客户端—服务器模型 + backend 控制同步逻辑。
1. 消息协议格式
客户端向 master 发送的包格式为:
1 |
|
- 总长度:网络字节序,不含自身;
- 操作码:
1=SET,2=GET,3=WAIT; key_len,value_len:后续字段长度;key,value:实际数据;- Master 解析后,回复:
OK/ value 内容 /READY等。
2. Rendezvous 阶段流程(2 机,4 卡 each,聚焦 rank1 & rank5)
1 | flowchart TB |
🧩 步骤解析
- Master 在端口(如 29500)侦听,接收连接;
- rank1 / rank5 分别发送
SET(注册地址); - 随后发送
WAIT("rendezvous_done"),Socket 处于阻塞状态; - Master 收集所有 8 个 rank 的
SET后,遍历wait阻塞的连接,逐一写入READY; - Worker 收到
READY,退出阻塞,进入 NCCL 初始化阶段; - 随后在这一阶段内:交换
ncclUniqueId(via store), 调用ncclCommInitRank构建通信组 (github.com, pytorch.org)。
3. Backend 细节对比
| Backend | I/O 模型 | 特点与适应性 |
|---|---|---|
| 经典 TCPStoreBackend | accept() + per-conn 阻塞/POLL |
简单,连接较多时扩展性差 |
| libuv 异步 Backend | 单线程 event-loop, readable/writeable |
默认启用(v2.4+),高并发更优 (docs.pytorch.org) |
- libuv backend 使用
uv_read_start自动分块读取,根据 header 控制拼包; - 注册
WAIT时,将 conn 保存在 map 中,不立即回写;当条件满足,触发uv_write()→uv_write_cb实现唤醒。
4. partial-key WAIT 机制
- 客户端可以执行
store.wait(["kA", "kB"]); - Master 将此等待登记至
MultiWaitRegistry; - 当 所有相关 key 均被
SET后,才统一向该连接写READY,触发唤醒。
5. “广播 READY” 的实现机制
- 不是通过 NCCL/Gloo broadcast 算子;
- Master 遍历挂起的 WAIT sockets,逐个写 READY;
- 为 rendezvous 过程自身提供同步机制,通信组尚未创建。
6. 时间线概览
1 | ┌──────────────────────────┐ |
✅ 总结要点
- 标注 rank1 / rank5 的流程图,更直观;
SET+WAIT操作全部发生于 rendezvous 阶段,见图;- Master “广播 READY” 是 socket 写操作,不是通信库广播;
- NCCL 初始化在 rendezvous 完成后进行;
- libuv backend 提供更高效 I/O 处理及 message 拼接处理能力 (docs.pytorch.org, pytorch.org, github.com)。