sskj/docs/dsv4pro_pro6000d_2node_sglang/6000D双机通信与NCCL术语入门.html

697 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>6000D 双机通信与 NCCL 术语入门</title>
<style>
:root {
color-scheme: light;
--ink: #17202a;
--muted: #5f6b76;
--line: #d9dee3;
--panel: #f5f7f8;
--cyan: #087b83;
--cyan-soft: #e5f4f3;
--orange: #a64b17;
--orange-soft: #fff0e5;
--green: #287a45;
--green-soft: #eaf6ee;
--red: #a73535;
--red-soft: #fdecec;
--code: #f0f2f4;
--max: 1160px;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
color: var(--ink);
background: #fff;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
"Hiragino Sans GB", "Microsoft YaHei", sans-serif;
font-size: 16px;
line-height: 1.72;
}
header {
color: #fff;
background: #172f35;
border-bottom: 5px solid #e57932;
}
.header-inner {
max-width: var(--max);
margin: 0 auto;
padding: 46px 28px 40px;
}
.eyebrow {
margin: 0 0 8px;
color: #9ed8d5;
font-size: 13px;
font-weight: 700;
text-transform: uppercase;
}
h1, h2, h3 { letter-spacing: 0; }
header h1 {
max-width: 850px;
margin: 0;
font-size: clamp(32px, 5vw, 54px);
line-height: 1.12;
}
.header-meta {
display: flex;
flex-wrap: wrap;
gap: 10px 22px;
margin-top: 22px;
color: #d4e4e5;
font-size: 14px;
}
.layout {
display: grid;
grid-template-columns: 240px minmax(0, 1fr);
gap: 38px;
max-width: var(--max);
margin: 0 auto;
padding: 34px 28px 70px;
}
nav {
position: sticky;
top: 20px;
align-self: start;
padding-right: 20px;
border-right: 1px solid var(--line);
}
nav strong {
display: block;
margin-bottom: 10px;
font-size: 13px;
color: var(--muted);
}
nav a {
display: block;
padding: 6px 0;
color: #40515a;
font-size: 14px;
text-decoration: none;
}
nav a:hover { color: var(--cyan); }
main { min-width: 0; }
h2 {
margin: 48px 0 16px;
padding-top: 8px;
font-size: 28px;
line-height: 1.25;
border-top: 2px solid var(--ink);
}
h2:first-child { margin-top: 0; }
h3 {
margin: 30px 0 10px;
font-size: 20px;
line-height: 1.35;
}
p { margin: 10px 0; }
a { color: var(--cyan); }
code {
padding: 2px 5px;
border-radius: 3px;
background: var(--code);
font-family: "SFMono-Regular", Consolas, monospace;
font-size: .92em;
}
pre {
overflow-x: auto;
margin: 14px 0;
padding: 16px 18px;
color: #e8f1f1;
background: #1c292d;
border-left: 4px solid #4cb3ae;
border-radius: 4px;
line-height: 1.55;
}
pre code {
padding: 0;
color: inherit;
background: transparent;
}
table {
width: 100%;
margin: 16px 0 24px;
border-collapse: collapse;
font-size: 14px;
}
th, td {
padding: 11px 12px;
text-align: left;
vertical-align: top;
border: 1px solid var(--line);
}
th {
color: #26363e;
background: #eef1f3;
}
ul, ol { padding-left: 24px; }
.note, .warning, .finding, .good {
margin: 18px 0;
padding: 15px 18px;
border-left: 4px solid;
border-radius: 4px;
}
.note { background: var(--cyan-soft); border-color: var(--cyan); }
.warning { background: var(--orange-soft); border-color: var(--orange); }
.finding { background: var(--red-soft); border-color: var(--red); }
.good { background: var(--green-soft); border-color: var(--green); }
.path {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 8px;
margin: 18px 0 24px;
}
.path div {
min-height: 108px;
padding: 12px;
border: 1px solid var(--line);
border-top: 4px solid var(--cyan);
background: var(--panel);
}
.path b { display: block; margin-bottom: 5px; }
.split {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 18px;
margin: 18px 0;
}
.split section {
padding: 16px 18px;
border: 1px solid var(--line);
border-radius: 4px;
}
.split h3 { margin-top: 0; }
.metric {
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
footer {
padding: 26px 28px 40px;
color: var(--muted);
text-align: center;
border-top: 1px solid var(--line);
}
@media (max-width: 900px) {
.layout { grid-template-columns: 1fr; }
nav {
position: static;
padding: 0 0 18px;
border-right: 0;
border-bottom: 1px solid var(--line);
}
nav a { display: inline-block; margin-right: 14px; }
.path { grid-template-columns: 1fr; }
.split { grid-template-columns: 1fr; }
}
@media print {
nav { display: none; }
.layout { display: block; max-width: none; }
header { color: #000; background: #fff; border-bottom-color: #000; }
.header-meta, .eyebrow { color: #333; }
pre { color: #000; background: #f4f4f4; }
}
</style>
</head>
<body>
<header>
<div class="header-inner">
<p class="eyebrow">Two-node communication primer</p>
<h1>6000D 双机通信与 NCCL 术语入门</h1>
<div class="header-meta">
<span>节点174.1.51.5 + 174.1.51.7</span>
<span>规模16 GPU / TP16</span>
<span>版本2026-07-30 17:54 CST</span>
</div>
</div>
</header>
<div class="layout">
<nav aria-label="目录">
<strong>阅读顺序</strong>
<a href="#mental-model">1. 一张总图</a>
<a href="#names">2. 设备名字</a>
<a href="#glossary">3. 核心术语</a>
<a href="#bootstrap">4. Bootstrap</a>
<a href="#parameters">5. NCCL 参数</a>
<a href="#logs">6. 日志怎么读</a>
<a href="#incident">7. 本次事故</a>
<a href="#checklist">8. 排查清单</a>
<a href="#sources">9. 官方资料</a>
</nav>
<main>
<h2 id="mental-model">1. 先建立一张总图</h2>
<p>
SGLang 不会自己搬运 16 张 GPU 之间的 Tensor。模型代码发起 TP/MoE 通信,
NCCL 决定用什么算法、经过哪条链路把数据送到其他 rank。
</p>
<div class="path" aria-label="通信路径">
<div><b>SGLang</b>执行模型层、TP16 和 EP2</div>
<div><b>Collective</b>AllReduce、AllGather、ReduceScatter、AllToAll</div>
<div><b>NCCL</b>构造 rank、ring/tree 和 channel</div>
<div><b>Transport</b>机内 P2P/IPC跨机 NET/IB 或 NET/Socket</div>
<div><b>硬件</b>GPU、PCIe、HCA、网卡、光模块、交换机</div>
</div>
<div class="note">
<strong>最重要的区分:</strong>
<code>NCCL bootstrap</code> 是“启动时要完成的一件事”;
<code>NCCL_SOCKET_IFNAME</code> 是“选择 IP 网卡的一个参数”;
<code>NET/IB</code><code>NET/Socket</code> 才是 NCCL 实际搬运数据的传输后端。
</div>
<h3>两类跨机路径</h3>
<div class="split">
<section>
<h3>理想路径RDMA</h3>
<p><code>GPU → HCA → RoCE 网络 → HCA → GPU</code></p>
<p>日志应出现 <code>NET/IB</code>,支持时还会出现 <code>GDRDMA</code></p>
</section>
<section>
<h3>回退路径TCP Socket</h3>
<p><code>GPU/CPU → Linux Socket → ethX → TCP/IP → ethX</code></p>
<p>日志会出现 <code>Using network Socket</code>。这不是报错,但性能通常低得多。</p>
</section>
</div>
<h2 id="names">2. eth0 和 mlx5_0 不是同一个设备</h2>
<div class="note">
<strong>400G 是物理 Ethernet 端口的标称链路速率。</strong>
<code>eth0</code> 是该端口的 Linux netdev/IP 入口;
<code>mlx5_0</code> 是映射到该端口的 RDMA Verbs/HCA 入口。
二者相关联,但不相等,也不代表 TCP 或 RDMA 应用一定能跑到 400G。
</div>
<table>
<thead>
<tr><th>名字</th><th>属于哪一层</th><th>负责什么</th><th>本机实例</th></tr>
</thead>
<tbody>
<tr>
<td><code>eth0</code></td>
<td>Linux IP 网卡接口</td>
<td>配置 IP、TCP/UDP、路由<code>NCCL_SOCKET_IFNAME</code> 选择</td>
<td>400 Gbit/s 计算网</td>
</tr>
<tr>
<td><code>eth3</code></td>
<td>Linux IP 网卡接口</td>
<td>第二条计算网 Rail</td>
<td>400 Gbit/s 计算网</td>
</tr>
<tr>
<td><code>mlx5_0</code></td>
<td>RDMA HCA / Verbs 设备</td>
<td><code>NET/IB</code> 使用;由 <code>NCCL_IB_HCA</code> 选择</td>
<td>对应 <code>eth0</code>,挂 switch 1</td>
</tr>
<tr>
<td><code>mlx5_3</code></td>
<td>RDMA HCA / Verbs 设备</td>
<td>第二条 RDMA Rail</td>
<td>对应 <code>eth3</code>,挂 switch 2</td>
</tr>
<tr>
<td><code>/dev/infiniband/uverbs0</code></td>
<td>Linux 字符设备</td>
<td>容器进程访问 RDMA Verbs 的入口</td>
<td>对应 <code>mlx5_0</code></td>
</tr>
</tbody>
</table>
<pre><code>mlx5_0 port 1 ==> eth0 (Up)
mlx5_3 port 1 ==> eth3 (Up)</code></pre>
<p>
同一条物理端口可以同时暴露 Linux IP 接口和 RDMA HCA。
<code>eth0</code> 是 IP/Socket 世界的入口,<code>mlx5_0</code> 是 RDMA
Verbs 世界的入口。<code>ibdev2netdev</code> 输出的是映射关系,不是等号。
本项目部署时只把 <code>eth0/eth3</code> 作为节点间计算网。
</p>
<pre><code>同一条 400G 物理 Ethernet 端口
├── eth0 -> Linux netdev -> IP / TCP Socket
└── mlx5_0 -> RDMA HCA -> RoCE / Verbs / GDRDMA</code></pre>
<p>
<code>400 Gbit/s = 50 GB/s</code> 只是单方向理论线速。协议开销、PCIe、
CPU、Socket 线程、消息大小和 collective 算法都会让实际
<code>algbw/busbw</code> 低于或采用不同统计口径。
</p>
<h2 id="glossary">3. 核心术语字典</h2>
<table>
<thead>
<tr><th>术语</th><th>通俗解释</th><th>在本项目中的意义</th></tr>
</thead>
<tbody>
<tr>
<td><strong>NCCL</strong></td>
<td>NVIDIA 的多 GPU 通信库,负责高效实现 collective 和点对点通信。</td>
<td>SGLang TP16 每层跨 GPU 通信最终大量落到 NCCL。</td>
</tr>
<tr>
<td><strong>rank</strong></td>
<td>一个通信参与者的编号。TP16 communicator 有 rank 015。</td>
<td>两台机器各 8 个 GPU rank共 16 个。</td>
</tr>
<tr>
<td><strong>collective</strong></td>
<td>一组 rank 共同参与的通信操作。</td>
<td>TP 常见 AllReduce、AllGather、ReduceScatterMoE 还可能有 AllToAll。</td>
</tr>
<tr>
<td><strong>RDMA</strong></td>
<td>远端直接内存访问。网卡可直接读写远端内存,减少 CPU 和内核数据拷贝。</td>
<td>双机 TP16 希望使用的高速数据路径。</td>
</tr>
<tr>
<td><strong>IB</strong></td>
<td>InfiniBand。既是一套高速网络体系也常被 NCCL 用作 Verbs/RDMA 后端的统称。</td>
<td>NCCL 日志里的 <code>NET/IB</code> 也可承载 RoCE不代表交换机一定是原生 IB。</td>
</tr>
<tr>
<td><strong>RoCE</strong></td>
<td>RDMA over Converged Ethernet在以太网上承载 RDMA。</td>
<td>本项目的 400G 计算网类型。</td>
</tr>
<tr>
<td><strong>HCA</strong></td>
<td>Host Channel Adapter提供 RDMA 能力的适配器。</td>
<td><code>mlx5_0</code><code>mlx5_3</code></td>
</tr>
<tr>
<td><strong>GDRDMA</strong></td>
<td>GPUDirect RDMA让 HCA 直接访问 GPU 显存,减少经 CPU 内存中转。</td>
<td>跨机 GPU 通信的理想路径,日志可见 <code>via NET/IB/.../GDRDMA</code></td>
</tr>
<tr>
<td><strong>Socket / TCP</strong></td>
<td>普通 IP 网络编程路径。NCCL 找不到 RDMA 时会使用。</td>
<td>本次脚本实际发生的回退路径。</td>
</tr>
<tr>
<td><strong>Rail</strong></td>
<td>一条相对独立的网络通道,通常由一张 HCA 和一套交换路径组成。</td>
<td><code>mlx5_0/switch 1</code><code>mlx5_3/switch 2</code> 是双 Rail。</td>
</tr>
<tr>
<td><strong>ring / tree</strong></td>
<td>NCCL 对 collective 的通信拓扑组织方式。</td>
<td><code>NCCL_CROSS_NIC</code> 决定同一 ring/tree 能否跨不同 NIC。</td>
</tr>
<tr>
<td><strong>PFC / ECN</strong></td>
<td>RoCE 网络控制拥塞和丢包的机制。</td>
<td>RDMA 出现 retry、pause 或吞吐抖动时由运维检查。</td>
</tr>
</tbody>
</table>
<h2 id="bootstrap">4. NCCL bootstrap 到底是什么</h2>
<p>
NCCL 本身不是进程启动器。SGLang 先启动各个 workerNCCL communicator 初始化时,
rank 之间需要交换地址、唯一 ID、拓扑和连接信息这段“先认识彼此”的过程就是 bootstrap。
</p>
<ol>
<li>每个 rank 启动并获得自己的 rank ID。</li>
<li>通过 IP Socket 交换 NCCL unique ID 和连接信息。</li>
<li>NCCL 探测 GPU、PCIe、HCA 和节点拓扑。</li>
<li>构造 ring/tree/channel。</li>
<li>选择真正的数据传输后端P2P、SHM、NET/IB 或 NET/Socket。</li>
</ol>
<div class="warning">
<strong>容易误解的地方:</strong>
<code>NCCL_SOCKET_IFNAME</code> 不保证“只用于 bootstrap”。
RDMA 正常时它主要承担 bootstrapRDMA 失败并回退 Socket 后,它也会决定大块 Tensor
数据走哪张 IP 网卡。
</div>
<h2 id="parameters">5. 常见 NCCL 参数</h2>
<h3>NCCL_SOCKET_IFNAME</h3>
<p>筛选 NCCL 可使用的 Linux IP 接口。精确指定接口时可写:</p>
<pre><code>NCCL_SOCKET_IFNAME="=eth0"</code></pre>
<ul>
<li>RDMA 正常:主要影响 bootstrap/OOB IP 连接。</li>
<li>RDMA 不可用:决定 <code>NET/Socket</code> 的数据网卡。</li>
<li>部署时只允许使用计算网 <code>eth0/eth3</code>Socket 回退时不能落到其他接口。</li>
</ul>
<h3>NCCL_IB_HCA</h3>
<p>筛选 NCCL 的 RDMA HCA。推荐使用精确匹配</p>
<pre><code>NCCL_IB_HCA="=mlx5_0:1,mlx5_3:1"</code></pre>
<p>
这个变量只是“允许选择谁”,不会自动把宿主机 RDMA 设备送进容器。
容器还必须看到 <code>/dev/infiniband/rdma_cm</code>
<code>uverbs0</code><code>uverbs3</code>
</p>
<h3>NCCL_CROSS_NIC</h3>
<table>
<thead>
<tr><th></th><th>行为</th><th>适用直觉</th></tr>
</thead>
<tbody>
<tr>
<td><code>0</code></td>
<td>尽量让同一 ring/tree 在不同节点使用对应的同一条 Rail。</td>
<td>每张 NIC 接不同交换机、跨 Rail 代价高的 rail-optimized 网络。</td>
</tr>
<tr>
<td><code>1</code></td>
<td>允许同一 ring/tree 在不同节点使用不同 NIC。</td>
<td>所有 NIC 进入同一网络 Fabric跨 NIC 不构成额外问题。</td>
</tr>
<tr>
<td><code>2</code></td>
<td>优先对应同一 NIC但必要时允许跨 NIC。</td>
<td>NCCL 默认的折中策略。</td>
</tr>
</tbody>
</table>
<div class="note">
本项目的 <code>mlx5_0</code><code>mlx5_3</code> 分挂 switch 1/2
拓扑直觉上更偏向 <code>0</code> 或默认 <code>2</code>。最终值必须在
<strong>真正启用 NET/IB 后</strong>用 all_reduce 和 SGLang 端到端 A/B 决定。
当 NCCL 使用 NET/Socket 时,这个参数不参与路径选择。
</div>
<h3>NCCL_DEBUG 与 NCCL_DEBUG_SUBSYS</h3>
<pre><code>NCCL_DEBUG=INFO
NCCL_DEBUG_SUBSYS=INIT,NET,GRAPH,TUNING</code></pre>
<p>用于确认实际路径,诊断完成后应关闭,正式性能数据不要长期带 INFO 日志。</p>
<h2 id="logs">6. NCCL 日志速查</h2>
<table>
<thead>
<tr><th>日志</th><th>含义</th><th>判断</th></tr>
</thead>
<tbody>
<tr>
<td><code>Bootstrap: Using eth0:...</code></td>
<td>初始化控制连接选择 eth0。</td>
<td>只说明 bootstrap尚不能证明数据走 RDMA。</td>
</tr>
<tr>
<td><code>NET/IB : Using ... mlx5_0 ...</code></td>
<td>NCCL 已识别 RDMA HCA。</td>
<td>RDMA 数据后端可用。</td>
</tr>
<tr>
<td><code>via NET/IB/.../GDRDMA</code></td>
<td>跨机边通过 GPUDirect RDMA。</td>
<td>理想证据。</td>
</tr>
<tr>
<td><code>NET/IB : No device found</code></td>
<td>容器没有可用 RDMA 设备或驱动/权限不完整。</td>
<td>继续看是否回退 Socket。</td>
</tr>
<tr>
<td><code>NET/Socket : Using 非计算网...</code></td>
<td>跨机数据由普通 TCP Socket 传输。</td>
<td>若误入低速非计算网,性能会严重受限。</td>
</tr>
<tr>
<td><code>via P2P/IPC</code></td>
<td>同机 GPU 通过 CUDA P2P/IPC。</td>
<td>机内路径,不代表跨机路径。</td>
</tr>
</tbody>
</table>
<h2 id="incident">7. 2026-07-30 Prefill 变慢事故复盘</h2>
<h3>已观测事实</h3>
<ul>
<li>宿主机存在 <code>/dev/infiniband</code>,两条 400G Rail 均 Up。</li>
<li>原脚本容器内不存在 <code>/dev/infiniband</code></li>
<li>NCCL INFO 明确打印 <code>NET/IB : No device found</code><code>Using network Socket</code></li>
<li>原脚本选择 400G 计算网 <code>eth0</code>quick-map 曾误选低速非计算网。</li>
<li>部署规定只有 <code>eth0/eth3</code> 用于节点间通信,两者均为 400G。</li>
</ul>
<table>
<thead>
<tr><th>冷缓存 Shape</th><th>原脚本网络eth0 Socket</th><th>quick-map错误的非计算网</th><th>差异</th></tr>
</thead>
<tbody>
<tr>
<td>1K → 1, C=1</td>
<td class="metric">TTFT 1.458s / 693.1 input tok/s</td>
<td class="metric">TTFT 15.8816.04s / 约 64 tok/s</td>
<td>约 10.9×</td>
</tr>
<tr>
<td>32K → 1, C=1</td>
<td class="metric">TTFT 38.062s / 860.5 input tok/s</td>
<td class="metric">TTFT 504.44s / 64.96 tok/s</td>
<td>约 13.25×</td>
</tr>
</tbody>
</table>
<div class="finding">
<strong>根因判断:</strong>
quick-map 没有把 RDMA 设备透传进容器,却把 <code>NCCL_SOCKET_IFNAME</code>
设成低速非计算网。NCCL 回退 NET/Socket 后TP16 跨机数据没有进入规定的
<code>eth0/eth3</code> 计算网。<code>NCCL_CROSS_NIC=1</code> 在没有 NET/IB
的情况下不是致因。
</div>
<h3>为什么旧日志还会比 38 秒更短</h3>
<p>
旧矩阵脚本还有第二个独立因素:<code>warmup_requests=16</code>、固定
<code>seed=42</code>、ISL/OSL/C 升序运行,而且从不 flush Prefix Cache。
因此旧日志混入缓存命中,不能直接与冷 Prefill 比较。
</p>
<div class="good">
quick-map 现在只允许 <code>eth0/eth3</code>
<code>mlx5_0/mlx5_3</code>,并会透传精确 RDMA 设备、强制检查两端
<code>NET/IB</code> 日志。代码与 dry-run 已通过;下一步是真机启动验证,
在拿到运行时证据前不进入 Kernel 归因。
</div>
<h2 id="checklist">8. 从宿主机到 NCCL 的排查清单</h2>
<ol>
<li>
<strong>宿主机链路:</strong>
<code>ethtool eth0</code><code>ethtool eth3</code>
</li>
<li>
<strong>HCA 映射:</strong>
<code>ibdev2netdev</code>,确认 <code>mlx5_0→eth0</code>
<code>mlx5_3→eth3</code>
</li>
<li>
<strong>宿主机设备:</strong>
<code>ls -l /dev/infiniband</code>
</li>
<li>
<strong>容器设备:</strong>
<code>docker exec CONTAINER ls -l /dev/infiniband</code>
宿主机有、容器没有NCCL 仍然用不了 RDMA。
</li>
<li>
<strong>运行时证据:</strong>
用一次 <code>NCCL_DEBUG=INFO</code> 启动,搜索
<code>NET/IB</code><code>NET/Socket</code><code>GDRDMA</code>
</li>
<li>
<strong>硬件计数器:</strong>
同时观察 eth0/eth3 流量和 RDMA 端口计数;不能只看环境变量。
</li>
<li>
<strong>端到端 A/B</strong>
冷缓存、同一 prompt、同一模型参数仅改变一个网络变量。
</li>
</ol>
<h3>最小 RDMA 设备透传验证</h3>
<pre><code>docker run --rm \
--device=/dev/infiniband/rdma_cm \
--device=/dev/infiniband/uverbs0 \
--device=/dev/infiniband/uverbs3 \
IMAGE \
ls -l /dev/infiniband</code></pre>
<p>
能看到设备只是第一关。最终仍必须从 NCCL INFO 中看到 <code>NET/IB</code>
并通过通信基准与 SGLang 结果确认。
</p>
<h2 id="sources">9. 官方资料</h2>
<ul>
<li>
<a href="https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/setup.html">
NVIDIA NCCL Setupbootstrap 与通信安全边界
</a>
</li>
<li>
<a href="https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/env.html">
NVIDIA NCCL Environment VariablesSOCKET_IFNAME、IB_HCA、CROSS_NIC
</a>
</li>
<li>
<a href="https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/troubleshooting/networking_troubleshooting.html">
NVIDIA NCCL Networking Troubleshooting
</a>
</li>
</ul>
<p>
<a href="./推理优化计划.html">返回推理优化主计划</a>
</p>
</main>
</div>
<footer>
本页以两台 6000D 的真实设备映射和 2026-07-30 实测日志为例。
</footer>
</body>
</html>