03 智算运维|丢 0.1% 的包,8 卡训练为什么会崩

《从裸机到推理服务》· 03 / 12

不用交换机权限,一条命令造出丢包,看 16 张卡怎么从「飞快」变成集体卡死。

预计 1 小时 | 前置:两台各 8 卡、装了 NCCL 与 nccl-tests(第 2 篇那两台);没有 8 卡也能做,降级方案在文内


给 .12 的网卡加 0.1% 丢包,只加 0.1%。

再跑一次集合通信:链路速率满格,GPU 一张没坏,16 张卡卡死了。

参数面怕的不是慢,是丢。这一篇把这件事演出来,再看「无损网络」靠什么把丢包摁住。

这一篇的产出

一条造丢包的命令(和用完删掉的习惯)、一张「丢包率 → busbw」对照表,以及一句能说出口的判断:参数面的事故,先查丢包,再查带宽。


一、崩的那一步,卡在等什么

先把那一秒拆开。三台各放一份完整模型,24 张卡分到的数据各不相同(全局 batch 切成 24 份),各自前向、各自反向,算出 24 份梯度;一步结束时把这 24 份加起来求平均,每台拿同一份平均值,各更新各的参数。这叫数据并行,绝大多数集群的默认做法。

所以三台都在算,没有主从。rank0(全局 0 号进程)只多负责打印日志、存 checkpoint,计算量不比别人多一个 FLOP。

一步的顺序只有四段:读数据 → 前向算 loss、反向算梯度 → 汇总梯度 → 各自更新。只有第三段跨机器,前后三段都在本机内完成。

↳ AllReduce:汇总梯度用的那套操作,把各卡算出的梯度加成一个结果,人人都拿到一份。

跨机器传的为什么只有梯度,两层原因:

  • 数据不流动:每台读自己那份,读多少由全局 batch 除以机器数定,跨机交换数据没有意义;
  • 参数不必流动:三台本来就一样,需要对齐的是「各台算出来不一致」的梯度。

口语里常说「同步参数」,传的其实是梯度。两者形状相同、含义不同:参数是模型本身,梯度是这一步该往哪改。参数只在训练开始时从 rank0 广播一次,之后靠梯度对齐。

于是三张网的分工就定死了:

流的是什么 走哪张网 频率
梯度(AllReduce) 参数面 每个 step,最频繁
训练数据、checkpoint 落盘 存储面 每 step 读、每 N 步写
日志、SSH、监控 管理面 随时,量极小

↳ checkpoint:训练中途把参数和优化器状态存成文件,崩了能接着跑。动辄几百 GB,走存储面。

回到开头那一秒:四段里唯一跨机的那一段,就是 16 张卡必须同时站住的时刻。前面算得再快,这一段慢,全都白等。

二、为什么 0.1% 就够 16 张卡全体停下

AllReduce 的规矩:一步里所有 rank 到齐,缺一个,其余的干等。Ring 实现里每人只和左右邻居收发,环上一环慢,整条环慢。

第二条是数学:走内核协议栈(TCP)的链路上,吞吐和丢包率大致是 吞吐 ∝ 1/√丢包率。丢包涨十倍,吞吐掉三倍多;从 0 涨到 0.1%,对每秒发几十万个包的集合通信来说,注定有包中招。

第三条最容易被忽略:RDMA 丢包比 TCP 更贵。IB 链路靠 credit 收发,本来就丢不了;RoCE 丢了包,传输层按 Go-Back-N 重传------从丢的那个包起,后面整段全部重发。TCP 至少只补丢的,RDMA 连好的一起重来。

所以三张网里只有参数面必须是「无损网络」:

↳ PFC :交换机对「不许丢」的那一档流量,队列快满时先喊停发送端。不丢包,代价是对端整口停发,调不好会连累别的流量。

↳ ECN :交换机在队列将满时给包打标记,发送端见标记就降速。不喊停,靠提前减速绕开丢包。

↳ 无损网络:靠 PFC、ECN 这些机制,把「不丢包」从运气变成配置保证。参数面的前提。

一个粗短的比喻:PFC 是路口「先停再走」,ECN 是「看见前方排队就松油门」,都是为了让包落不到「丢了再补」那一步。

顺带说清:加机器解决的是时间,不是容量。 单机卡在哪,决定了该不该加机器:

单机卡在哪 数据并行管用吗 该用什么
算力不够,跑得太慢 管用 数据并行,8→16 卡典型加速 1.7---1.85 倍
显存装不下模型或优化器状态 不管用 切模型:张量并行、流水并行,或 ZeRO / FSDP 分片
装不下大 batch 不用多机 梯度累积,攒几步再更新一次
一台盘装不下训练数据 与并行方式无关 共享存储,第 08 篇

数据并行的前提是「一台机器装得下整个模型」------它买的是时间,不是容量。装不下时,模型必须被切开,参数就不再每台一份:

↳ ZeRO / FSDP:把参数、梯度、优化器状态按卡数切开,每张卡只存 1/N,需要时向别人取。显存降下来了,代价是通信从「每步一次梯度平均」变成「每层都要取参数」。

那时参数面吃的不只是梯度,还有来回复制的参数分片,流量比这一篇的场景大一个量级。本篇讲的是放得下、要更快的那一类,也是绝大多数集群的日常。

三、把丢包造出来

实验只在 .11、.12 两台上做,16 卡,道理相同、规模减半。

第一步:在真参数面上拿基线

nccl-tests 的 all_reduce_perf 跑一次 Ring AllReduce,.11 和 .12 各 8 卡:

bash 复制代码
mpirun -np 2 -H hostfile ./all_reduce_perf -b 512M -e 512M -g 8
复制代码
#       size         count      type   redop    root     time   algbw   busbw
#        (B)    (elements)                               (us)  (GB/s)  (GB/s)
    536870912    134217728     float     sum      -1    5284.1    96.9  181.6

看 busbw,不看 time:它是链路上实际搬动的速率,181.6 GB/s 对两台各 8×200G 的聚合线速是 90%------和第 2 篇测到的比例对上了。hostfile 两行,.11、.12 各一行。

第二步:把通信指到能被拦住的路上

坏消息先说:tc netem 作用在内核的发送队列上,拦不住 RDMA 流量------参数面的数据从用户态直通网卡,绕过内核。想造丢包,先让 NCCL 走一遍内核协议栈:

bash 复制代码
export NCCL_IB_DISABLE=1          # 不走 IB
export NCCL_SOCKET_IFNAME=eno2    # 走存储面那张以太网卡
mpirun -np 2 -H hostfile ./all_reduce_perf -b 512M -e 512M -g 8
复制代码
    536870912    134217728     float     sum      -1   89123.4     6.0   11.3

同一个测试,busbw 从 181.6 掉到 11.3 GB/s------这是普通以太网(100G)跑集合通信的真实水平。拿它当基线,丢包的效果才量得出来。

第三步:加丢包,一次只加一档

↳ tc netem:内核自带的网络模拟工具,不用交换机权限,就能给指定网卡造丢包、延迟、抖动。

bash 复制代码
# 在 .12 上执行
sudo tc qdisc add dev eno2 root netem loss 0.1%
tc qdisc show dev eno2
复制代码
qdisc netem 8001: root refcnt 2 limit 1000 loss 0.1%

loss 0.1% 已生效:每 1000 个包丢 1 个。netem 只管这张卡的出方向,双向都丢得在两台各加一条。逐档重跑第一步的命令,每档记一行:

丢包率 algbw (GB/s) busbw (GB/s) 现象
0(TCP 基线) 6.0 11.3 正常
0.01% 2.3 4.3 明显变慢
0.1% 0.4 0.8 慢到没法用
1% --- --- 600 秒后被 watchdog 收掉

丢包率十倍十倍地涨,吞吐三到五倍地掉,对得上 1/√丢包率。0.1% 看着小,一次 AllReduce 要发几十万个包,注定有包中招;一个包中招,整条环陪着重传。

第四步:看它怎么死

丢包加到 1%,带上 NCCL 日志:

bash 复制代码
NCCL_DEBUG=INFO mpirun -np 2 -H hostfile ./all_reduce_perf -b 512M -e 512M -g 8
复制代码
node12:3821:4103 [3] NCCL WARN Complete callback timeout for op 7 after 600 seconds
node12:3821:4103 [3] NCCL INFO aborting: watchdog timeout

600 秒是 watchdog 的默认时长。死法值得看清:不是报错退出,是先卡死------16 个 rank 全部挂在同一个集合操作上等重传,GPU 利用率归零、显存不释放、日志一行不发,600 秒后才被看门狗收割。生产环境里半夜告警的「训练 hang 住」,多数长这样。

第五步:删掉它,再确认删干净

bash 复制代码
sudo tc qdisc del dev eno2 root
tc qdisc show dev eno2
复制代码
qdisc noqueue 0: root refcnt 2

回到 noqueue 才算恢复。这一步不是仪式:不删,.12 之后所有出方向流量都在静悄悄丢包,包括明天别人的实验。

只有一台机器怎么办

单机跑 all_reduce_perf 只走 NVLink,碰不到网卡,整套实验做不了。退一步用回环口:

复制代码
$ sudo tc qdisc add dev lo root netem loss 0.1%
$ iperf3 -c 127.0.0.1 -t 10
[ ID] Interval           Transfer     Bitrate         Retr
[  4]   0.00-10.00  sec  1.72 GBytes   1.48 Gbits/sec   2143   sender

回环口本来能跑到 20 Gb/s 量级,0.1% 丢包把它压到 1.5 Gb/s,重传两千多次------TCP 世界里丢包的下场和参数面同源,只是看不到「卡死」:那是 16 张卡互相等的集体行为。用完同样删掉。

四、先看「丢没丢」,再看「跑多快」

真实故障里没人帮着加 netem,丢包是自然发生的:光模块劣化、PFC 配错、交换机缓存溢出。查法和实验相反------先看计数器,再跑带宽:

bash 复制代码
sudo ethtool -S mlx5_0 | grep -iE "crc|out_of_seq|resend"
复制代码
     rx_crc_errors: 0
     packet_seq_resend: 47
     out_of_sequence: 12

packet_seq_resend、out_of_sequence 不为零或在涨,说明传输层正在重传、遇到乱序,这就是「卡死」的源头;rx_crc_errors 有数,先换线换模块。和第 2 篇合起来才是完整的链路体检:速率对不对(第 2 篇)、丢没丢(这一篇),两样都干净,才轮到怀疑代码。

RoCE 环境还要多看一眼

PFC 和 ECN 有各自计数器:ethtool -S eth2 | grep -iE "pfc|cnp"。PFC 帧暴涨是喊停喊得太频繁(配得过猛),CNP(ECN 标记包)暴涨是拥塞真实存在。这两个数字是网络工程师调无损网络的仪表盘。

处置:先分「线坏」还是「拥塞」,再决定找谁

三个计数器就能把方向分开,不必等别人:

  • rx_crc_errors 在涨 → 物理层。换线、换模块、擦端面,这些自己能做;
  • CRC 不动,packet_seq_resend、out_of_sequence 在涨 → 拥塞或 PFC 反压,交换机侧的事;
  • 三项都干净,训练还是慢 → 不是丢包,回第 2 篇查速率和 PCIe。
现象 判断 动作 归谁
CRC 涨 线或模块在劣化 换线换模块,记下更换前后的计数差 现场
重传涨、CRC 不动 拥塞、缓存溢出、PFC 反压 停掉同链路其他流量复测;查交换机端口利用率 网络
只有个别 rank 慢 那一条 rail 或那一张卡 换端口、换卡槽,把范围缩到单链路 自己
训练 hang、日志里是 watchdog 已经到「卡死」这一档 先抓 dmesg、计数器、NCCL 日志,再重启 自己
RoCE 环境 CNP 暴涨 拥塞真实存在 调 ECN 门限与 PFC,交换机侧动作 网络

两条纪律,比上面任何一步都容易踩:

  • 重启会洗掉计数器。 抓完再重启。反过来做,第二天手上只剩一句「昨晚它卡了」。
  • 调大 NCCL_IB_TIMEOUT 不是修复。 它只是让程序多等一会儿,把「卡死」变成「更久的卡死」,现场看起来像是好了。

五、最容易卡住的五处

坑一:netem 加了,数字纹丝不动

参数面流量绕过内核,netem 拦不住,第一步就该想到。要么让 NCCL 走以太网(第二步的两个环境变量),要么在 RoCE 环境从交换机侧造拥塞。实验没效果,先查这一条,不是先怀疑工具。

坑二:NCCL 自己挑了别的网口

不指定 NCCL_SOCKET_IFNAME,NCCL 可能挑到 docker0 或回环口,甚至走本机共享内存------数据根本没出网卡,什么实验都测不出来。固定到实验网卡。另外 eno2 上还跑着 NFS,实验时段和别人的数据读写错开。

坑三:netem 用完不删

第五步的 del 加 show 是一套动作。漏了删,故障被留在了机器上;漏了 show,删没删成不知道。

坑四:把 busbw 当带宽报

busbw 含 Ring 通信的冗余传输,天然比 algbw 大。报数带口径:「algbw X,busbw Y(Ring 16 卡)」,否则和第 2 篇的链路带宽对不上,越对越糊涂。

坑五:不留基线

丢包 0 的那两行数字是整套实验的锚。删环境前把表存下来,和第 2 篇的三行表放在一起。

六、怎么算做完了

验收标准

① 一张四行表:丢包 0 / 0.01% / 0.1% / 1% 各自的 busbw 和现象;

② 一套能复现的命令:加丢包 → 跑测试 → 删丢包 → 确认恢复 noqueue;

③ 一句话结论:这条链路无丢包时 busbw X GB/s;丢包率每升十倍,吞吐掉三到五倍------参数面必须是无损网络,原因就在这张表里。

企业里这活归谁:PFC、ECN 由网络工程师在交换机上配置,交付验收时要看他们的无损属性测试报告。运维的职责是发现:看计数器(第四节)、认日志里的 watchdog(第五节),把「网络是不是有问题」回答成带数字的问题。


下一篇:.11 重启之后卡在自检。不装系统、不进 BIOS 也进得去------从 BMC 开始,把一台开不了机的机器救回来。


命令与判读方法整理自 NVIDIA NCCL 文档、nccl-tests 仓库、Linux tc/netem 手册与 RDMA 运维社区帖。输出示例为通用配置,数字区间为公开资料中的常见范围,实际以现场为准。如有错漏,欢迎指出。

相关推荐
汤姆宝库31 分钟前
权重量化的实现:从absmax到GPTQ与AWQ
人工智能
硅谷秋水1 小时前
PhysicalWords:一种用于构建机器人操作中潜推理过程的词汇体系
人工智能·机器学习·计算机视觉·语言模型·机器人
喵个咪1 小时前
GoWind 拆解:AI Agent 编排引擎——波次并行、子图递归与人工审批
人工智能·后端·go
ZzT2 小时前
AI 是放大器:基础越扎实,放大效果越明显
人工智能·ai编程
喵个咪2 小时前
GoWind Admin 拆解:AI 能力层——工具循环、pgvector 知识库与机器凭证
人工智能·后端·agent
老金带你玩AI2 小时前
10秒出4K,MiniMax还开源了!H3 Image上线!
人工智能
mantou1323 小时前
只用 Cloudflare 全家桶,给游戏站做一个 RAG 搜索和问答
人工智能·llm
AI前端工程狮3 小时前
服务端已经死了,客户端却报"超时"
人工智能·程序员
阿屿3 小时前
从零手搓 AI 伴侣(二):好感度通胀危机,与它的「货币政策」
java·人工智能