一、引言
之前的文章中已经详细介绍过大规模 AI 集群中的常见问题以及运维实践,笔者也在大规模 LLM 训练、推理中支持过大量的问题排查和定位。这里借着字节的大规模 LLM 训练管理系统进行简单的回顾。
对应的论文:[2509.16293] Robust LLM Training Infrastructure at ByteDance [1]
相关工作可以参考:
-
大规模 GPU 集群运维实践:假装万卡 GPU 集群经验 -
聊聊 GPU 监控那些事:利用率 & 故障等 -
Meta 万卡 GPU 集群稳定性剖析与最佳实践 -
静默数据损坏(SDC):AI Infra 的隐性杀手 -
阿里云 SkeletonHunter:诊断与定位大模型训练中的网络故障 -
提升大模型训练 MFU:字节“拖后腿”现象分析和归因 -
Delta AI 集群的 GPU 故障分析和刻画 -
万卡 GPU 集群实战:探索 LLM 预训练的挑战
二、摘要
LLM 预训练的规模已达数万个 GPU,并在不断扩大。伴随着资源扩张而来的 CUDA Error,NaN,Hang,Timeout 等问题普遍存在,给训练稳定性带来极大挑战。
任何大规模 LLM 训练 Infra 都应争取最小的训练中断、高效的故障诊断和有效的故障容错,以实现高效持续训练。当然,也需要保障训练的有效性,比如在同样的算力预算下生产尽可能强大的模型,降低无效实验和任务;除此之外,也需要保证尽可能高的训练 MFU,提升算力利用率。
本文中,字节跳动提出了 ByteRobust,专为 LLM 稳定训练设计的大规模 GPU Infra 管理系统。其利用 LLM 训练过程中的独特性,将常规方式的故障诊断和恢复放在首位。利用 LLM 训练的并行性等特性,通过有效的数据驱动方案,可以实现大规模容错、即时故障定位,全面保障 LLM 任务的持续高效训练。
ByteRobust 部署在大规模 GPU 生产集群,在 9,600 GPU 上为期 3 个月的训练任务中实现了 97% 的 ETTR。
三、大规模训练的挑战
在数万 GPU 的超大规模集群上进行长达数月的 LLM 训练会面临以下主要挑战。
3.1 故障频繁
随着规模扩大,故障(如 CUDA Error、网络故障)几乎不可避免。例如 Llama 3([2407.21783] The Llama 3 Herd of Models [2]) 在 16K GPU 上训练时,54 天的训练中,遇到了 466 个任务中断,其中包括 47 次的有计划中断,以及 419 次的预期外中断,平均每 2.78 小时就会遇到故障。在这些非预期中断中,78% 是硬件问题,例如 GPU 或物理机其他组件的异常,其中 GPU 相关问题占到 58.7%。

如下图 Table 1 所示,ByteRobust 作者也总结了他们生产平台上 3 个月中所有 LLM 训练作业的训练故障,其包括:
显式故障:有比较清晰的诊断指标,例如 stdout 和 stderr 日志中的错误,特定的退出码等。
隐式故障:通常是 Hang,性能下降或者异常的训练 Loss 等,比较难定位。
手动重启:算法或工程持续迭代和优化,需要重启。

3.2 诊断困难
除了显式的报错,还存在大量隐式故障(Implicit Failures),如任务 Hang、性能下降(MFU 下降)或 loss 出现 NaN。这些故障没有明确的错误日志,传统方法难以定位。
常见的故障诊断系统会基于日志分析来监控任务状态,但是 Hang 时,任务在 Timeout 之前(比如 NCCL 默认是 30 分钟或 60 分钟 Timeout)不会产生任何日志。
当前的 LLM 训练基本都是同步训练模式,MFU 下降或波动时,所有的 IO、计算和通信的指标都会下降和波动,很难定位根因。
SDC 故障也很难处理,由于 LLM 的集合通信范式,单节点的梯度损坏可能污染所有参与的 Worker。
3.3 恢复成本高
传统的“停机-诊断-重启”流程耗时过长。在大规模场景下,精准定位故障根因往往导致大量 GPU 资源限制,代价过高。如下图 Figure 3 所示,以任务 Hang 等隐性故障为例,其多个阶段的处理流程导致大量资源的长时间停滞。

3.4 代码演进频繁
LLM 训练包含多个阶段,如下图 Figure 1 所示,比如 Warmup、General、Anneal 等,用户代码和配置需要频繁调整。除此之外,Infra 团队也会持续优化性能,提升 MFU,如下图 Figure 2 所示。这些场景都需要手动重启,这里也有个小 Trick:手动重启可以发生在刚保存完 Checkpoint 并且迭代了一些 Step 之后,这样从最新 Checkpoint 重启可以有一些重叠的 Step 验证各项指标是否对齐,对于工程优化尤其重要。


四、ByteRobust 方案
4.1 ByteRobust 设计哲学
ByteRobust 有几个核心理念,贯穿整个系统:
快速隔离 > 精准定位:有些时候精准定位周期很长,与其让万卡停滞不如快速缩小故障范围,直接隔离后重启。 64 卡停滞 10 小时的成本远小于 1 万卡停机 30 分钟的成本,合理的备机至关重要。
拥抱不完美的硬件:除了隔离也可以选择重试,作者基于 19 个大规模 LLM 训练任务(>= 9600 卡)的观察发现,直接隔离机器解决了 32.52% 的问题,而重试也可以解决 22.70% 的问题。
接受“人”的因素:硬件会故障,代码也经常会有 Bug,系统要能区分是 Infra 的问题还是用户代码的问题,并提供快速回滚和热更新机制。有种说法:Google Gemini 性能的不断提升,也和 Google 解决了一系列 Bug 密切相关。
4.2 ByteRobust 方案
如下图 Figure 4 所示,ByteRobust 系统旨在解决上面的一系列挑战,自动诊断和处理各种训练故障,同时尽可能减少非生产时间。其系统包括两个核心组件:
控制平面(Control Plane):包括:
Robust Controller 利用实时监控和停机诊断来处理大多数故障。在没有机器隔离时使用原地热更新机制重启训练。有机器隔离时,会请求通过自检验证的热备机器来恢复任务。
Runtime Analyzer:通过聚合来自训练 Pod 的堆栈信息来隔离和驱逐可疑机器,从而解决任务 Hang 和性能下降问题。
数据平面(Data Plane):在每个训练 Pod 中会运行一个 Robust Agent 守护进程,处理来自 Robust Controller 的控制信号并管理以下 4 个子模块:
Monitor:收集多个方面的数据以便检测 Outlier,支持实时检查,在异常时触发 Diagnoser。
Diagnoser:任务暂停后运行特定领域的基准测试和验证组件,以实现对复杂故障的深入诊断。
CKPT Manager:捕获训练进程的堆栈信息,并将其上传到 Runtime Analyzer。
On-demand Tracer:执行异步 Checkpointing 操作,并跨并行组备份到 CPU 内存和本地磁盘,最大化减少恢复成本。

4.3 自动容错
自动容错对于 LLM 的训练直观重要,可以最大限度减少故障检测、定位和解决的人工成本,极大限度降低非生产时间。其核心思路是:快速、粗粒度的故障隔离通常能比昂贵、细粒度的根因排查产生更好的权衡。
如下图 Figure 5 所示,其自动容错机制包括 2 个主要部分:
主动实时检查:
系统检查:
通过 Monitor 模块检查网络侧问题(NIC Down、抖动、丢包率、交换机 Down 等,可以利用 mlnx_perf 工具或者参考:NVIDIA DOCA Telemetry Service Guide [3]),GPU 侧问题(DCGM 服务状态,PCIe 带宽、Row remaping、GPU 温度等,可以通过 dcgm-exporter 获取:GitHub - NVIDIA/dcgm-exporter: NVIDIA GPU metrics exporter for Prometheus leveraging DCGM [4])以及 Host 侧问题(demsg 中的 Xid,以及内核 Event 事件等)。
一旦检测到任何异常(步骤 ①),Monitor 会上报给 Robust Agent,并进一步通知 Robust Controller。对于指向特定机器的高置信度事件,比如 GPU 不可用、磁盘故障等,Controller 会驱逐机器并立即停止所有进程。对于网络问题,允许有数次报警,如果持续频繁出现才驱逐。如果驱逐后重启训练再次失败,将进入停机检查过程。
指标收集:
包括 3 类指标:使用 wandb 收集训练任务的 loss,grad-norm,MFU 等指标;stdout/stderr 日志和进程退出码;Event 信息,包括 CUDA、RDMA、Host 以及存储 Event。
运行时,Controller 分析收集的指标,如果检测到用户空间错误,如 TypeError、IndexError,可以追溯到日志和退出代码的特定代码模块,则触发代码回滚(步骤 ②)。如果训练崩溃或出现异常指标(例如 loss NaN),且没有明确原因,暂停训练并运行停机检查(步骤 ③)。如果发现性能异常,比如 RDMA 持续 10 分钟没有流量,低 Tensor Active,则触发聚合分析以进行机器隔离。
分级停机检查:
诊断:Diagnoser 分析日志和退出码等以进行故障诊断,还会运行相应的测试来定位根本原因。比如方式 NCCL Internal Error 时,执行如下测试,发现的疑似异常机器可以进行驱逐(步骤 ④):
首先,运行 NVIDIA EUD(Extended Utility Diagnostics)来确认是否有 GPU 异常(可以参考 NVIDIA dcgmi 的相关工具:DCGM Diagnostics [5])。
然后,运行 all2all 测试验证机内 GPU 连接带宽是否符合预期(可以参考 nccl-tests 工具:NVIDIA/nccl-tests [6])。
最后:每台机器与相邻机器运行 all-gather 测试,以验证数据传输的连通性和完整性(同样可以参考 nccl-tests)。
重试:所有测试都通过,Diagnoser 假设故障是瞬态故障引起,直接重启训练任务(步骤 ⑤)。
回滚:如果重启无法解决(步骤 ⑥)或驱逐机器后再次崩溃(步骤 ⑦),Diagnoser 假设最近的用户代码可能有问题,通过热更新机制回滚用户代码,以移除最近集成的新功能。如果重启成功,则归因于用户代码问题。
双阶段重放:如果依然失败,则假设存在未知故障(比如 SDC),则进行双阶段、维度感知的重放,在保持原始 TP/PP 大小不变的同时仅改变 DP 大小(步骤 ⑧),考虑到模型规模可能比较大,可以适当降低模型层数,然后以水平组和垂直组对比的方式发现故障机器,并将其隔离(步骤 ⑨)。

如下图 Figure 6 所示,为双阶段重放中通过水平组和垂直组两组实验确定 SDC 机器的方案:

NaN Loss 诊断案例研究:如果 Monitor 监控到训练期间出现 NaN Loss,首先执行上述基准测试,如果所有测试都通过,则运行逐位校准测试:每台机器启动一个参考模型,模型结构与目标任务类似(Dense 或 MoE),都加载相同的 Checkpint,采用特定的并行配置(比如 TP=2, PP=2, DP=2 或 EP=2, PP=2, DP=2),并在固定数据上执行一个 Step,然后对所有机器的输出进行逐位对比,产生不正确结果的机器立即隔离。如果未识别到异常机器,则采用重试或回滚来解决潜在的瞬态故障和人为错误。如果训练依然失败,则应用双阶段重放测试进行故障排查。
4.4 数据驱动的冗余驱逐
当遇到任务 Hang 或者 MFU 下降时,为了精确定位异常位置,ByteRobust 会进一步聚合分析不同机器的调用堆栈。当然,仅分析主进程是不够的,还需要进一步分析子进程。针对这个场景,可以使用 py-spy(GitHub - benfred/py-spy: Sampling profiler for Python programs [7])来分析热点和瓶颈,也可以使用 pystack(GitHub - bloomberg/pystack: 🔍 🐍 Like pstack but for Python! [8])分析所有进程、线程的调用栈。基于此,可以进一步分析热点、堆栈行为中的 Outlier,并直接驱逐整个关联的并行组,从而快速恢复训练,不用等待数个小时的精确排查。
如下图 Figure 7 所示,展示了一个 SDC 导致的后向通信 Hang 的问题(也可以借助 nccl 最新的 Inspector 和 RAS 工具)。其中:
Machine 15 停在了 all_gather_into_tensor(PP 的最后一个 Stage,用于产生 Backward 的激活梯度阶段);
Machine 0-11 完成了 Backward 的所有 Kernel 启动,进入到 Optimizer 的梯度同步;
Machine 14 和 Machine 12-13 在为某些 Micro-Batch 传输梯度时分别阻塞在 isend 和 irecv 中。
ByteRobust 通过快速识别故障并行组来解决此问题:
首先,解析每个训练 Pod 的进程树,以识别与训练相关的进程,例如 torchrun、dataloader 和 checkpoint 进程。
其次,获取对应进程的堆栈,并通过字符串匹配聚合到多个分组以区分 Outlier,占据主导的组被认定为监控组,其余组视为 Outlier。
最后,找到这些 Outlier 的共享并行组进行相应的隔离。这个示例中,Machine 12/13/14/15 属于最后一个 PP Stage。

4.5 快速恢复机制
故障检测和定位后,ByteRobust 可以在一致的环境迅速重启训练,最大程度减少停机并避免新故障。具体来说,包括 3 个措施:
原地热更新 :允许在保留 Pod 环境的情况下更新代码和配置,减少重新调度的开销。
热备机器 :利用故障独立性假设,维护少量(P99 故障率覆盖)已初始化环境的备用机,实现秒级替换。备机池是动态补充的,每台新备机都会进行相应的自检以及镜像的安装等,然后进入低功耗睡眠模式。发生机器驱逐时,如果有足够备机,则会被立刻唤醒并加入训练;否则,将进行相应的补充。
过度驱逐感知 Checkpointing:Checkpoint 异步写入 CPU 内存和本地 SSD,并采用跨并行组备份策略。即使整个并行组被驱逐,也能从其他组的备份中恢复,避免回退到远程存储。
如下图 Figure 9 所示,任何一个并行组被驱逐,都能从其他并行组中获得相应备份的 Checkpoint:

当然,也不会让备份操作影响正常的训练进度,如下图 Figure 8 所示,ByteRobust 利用每个训练 Step 中的空闲通信周期,使用 P2P 通信让每个 Rank 与选定的备份机器的对等 Rank 交换 Checkpoint 分片。

五、评估和结果
5.1 环境
两个生产 GPU 集群,一个包含 1200 台机器,每台机器 8 个 Hopper 80GB GPU(H100/H800),通过 NVLink + NVSwitch 互联。另一个包含 1024 台机器,每台机器 16 个 L20 48GB GPU,通过 30GB/s PCIe 互联,共 16K GPU。所有机器都是 2T 内存,8 个 400Gbps 的后端网卡,96 Core Intel CPU。
5.2 生产环境评估
两个任务,一个为期 3 个月的 Dense 模型训练(70+B),一个为期一个月的 MoE 模型训练(200+B),都在 9600 GPU 的 Hopper(H100/H800)机器训练。
如下图 Table 3 所示为对应的监控间隔时间,比如 NIC 的检查间隔是 30s,GPU 高温检测的时间是 10S(GPU 高温会导致 GPU 降频,从而出现性能下降的问题,也会增加 SDC 概率),CPU 内核的检测间隔是 2s:

如下图 Table 4 展示了两个生产作业的故障解决比例,可以看出,大部分显式故障主要通过自动机器驱逐和重启训练任务解决,分别占两个任务中故障比例的 73.1% 和 56.8%。对于隐式故障(Hang,MFU 下降),分析器解决了 24 次故障,回滚识别了一些工程代码问题,两个任务中分别占 6.9% 和 11.2%。

如下图 Figure 9 和 Figure 10 所示,ByteRobust 可以将累积 ETTR 维持在 97% 的水平。而 ETTR 后期的下降和波动主要是因为工程团队首次部署了长上下文训练相关能力,导致多次代码故障。除此之外,通过不断调整和优化,MFU 逐渐提升,在 Dense 模型和 MoE 模型中分别实现了 1.25x 和 1.58x 的 MFU 提升(PS:当前 Dense 模型训练通常都能在起始阶段获得较高的 MFU;而 MoE 模型、多模态训练等则需要不断迭代持续优化)。

5.3 故障恢复的有效性
5.3.1 快速任务重启
如下图 Table 7 所示,在 5 次手动代码更改涉及的重启中(1024 机器会有 4 个备机),本文的热更新方案比重新排队的方案快 11.04x。

5.3.2 近乎零开销的 Checkpointing
作者也进一步对比了 ByteRobust 与业内常见 Checkpoint 保存方案,可以看出,本文的 Checkpoint 保存方式明显优于 Megatron-LM 的 Megatron Save 和 Google Gemini 的 Memory Save。

六、参考链接
https://arxiv.org/abs/2509.16293
https://arxiv.org/abs/2407.21783
https://docs.nvidia.com/doca/archive/2-8-0/nvidia+doca+telemetry+service+guide/index.html
https://github.com/NVIDIA/dcgm-exporter
https://docs.nvidia.com/datacenter/dcgm/latest/user-guide/dcgm-diagnostics.html
https://github.com/NVIDIA/nccl-tests
https://github.com/benfred/py-spy
https://github.com/bloomberg/pystack

