Robust LLM Training Infrastructure at ByteDance
Robust LLM Training Infrastructure at ByteDance
作者/机构: Borui Wan, Gaohong Liu, Zuquan Song, Jun Wang, Yun Zhang, Guangming Sheng, Shuguang Wang, Houmin Wei, Chenyuan Wang, Weiqiang Lou, Xi Yang, Mofan Zhang, Kaihua Jiang, Cheng Ren, Xiaoyun Zhi, Menghan Yu, Zhe Nan, Zhuolin Zheng, Baoquan Zhong, Qinlong Wang, Huan Yu, Jinxin Chi, Wang Zhang, Yuhan Li, Zixian Du, Sida Zhao, Yongqiang Zhang, Jingzhe Tang, Zherui Liu, Chuan Wu, Yanghua Peng, Haibin Lin, Wencong Xiao, Xin Liu, Liang Xiang (香港大学, 字节跳动)
A1 主要贡献
本文介绍了ByteRobust,一个为大规模语言模型(LLM)的稳健和稳定训练量身定制的大规模GPU基础设施管理系统。当前LLM的训练规模已达数万个GPU,伴随而来的是故障(如CUDA错误、NaN值、作业挂起等)的普遍发生,这对训练稳定性构成了重大挑战。现有故障处理方法依赖于故障停止后的日志分析和压力测试,恢复过程(重新调度资源、重载TB级检查点)会产生数小时甚至数天的开销,严重影响有效训练时间比率(ETTR)。
核心问题与挑战:
1. 隐式故障难以定位:许多错误如作业挂起、性能抖动、静默数据损坏(SDC)等没有明确的故障信号,传统基于超时的检测方法浪费了大量GPU算力。
2. 超大规模训练的复杂性:在数万GPU的规模下,即使定位到故障机器,也没有足够的备用机器来替换所有资源,使得故障机器的定位和隔离成为关键路径。
3. 用户代码的持续演进:长达数月的LLM预训练过程中,为了追求极致性能,需要不断集成性能优化或算法调整,这种代码的频繁迭代和重启引入了额外的复杂性,并且演进中的代码本身也可能成为新的错误来源。
研究目标与创新点:
为应对上述挑战,ByteRobust旨在实现高效的事件诊断和处理,最大限度地减少非生产性时间。其核心设计理念和贡献如下:
-
优先快速隔离,而非精确定位:ByteRobust倾向于快速故障隔离而非详尽的定位。它结合了轻量级实时检测和分层停机诊断,以最小开销快速筛选出故障机器。当这些方法不足时,ByteRobust应用数据驱动的运行时堆栈跟踪聚类,在定义的故障域(如并行组)内隔离可疑机器,并对其进行过度驱逐(over-evicting),而不是追逐确切的根本原因。
-
将人为错误纳入设计:认识到人为错误是不可避免的故障来源,ByteRobust的自动化容错框架将机器故障检测和诊断与代码回滚相结合,以实现快速验证和恢复。此外,通过一种惰性更新方法,利用故障的必然性和高频率,将用户代码的更改与确定性故障的处理合并。
-
在快速恢复期间控制可变性:
- 对于不改变机器分配的更改,使用原地热更新(in-place hot-update)机制来保留运行时环境并简化诊断。
- 为确保受控和快速的恢复,ByteRobust利用预先配置并通过自检的温备机(warm standbys),避免了完整的作业重新调度。
- 其检查点模块通过将备份分布在并行组之外,消除了对远程获取的依赖,从而与故障域相匹配,实现了快速重启。
ByteRobust已在一个拥有超过20万个GPU的生产GPU平台上部署,并通过其自动化容错训练框架,在三个月内识别了38,236个显式故障和5,948个隐式故障。在一个为期三个月、使用9,600个GPU的训练任务中,ByteRobust实现了97%的ETTR,展现了其在训练鲁棒性方面的先进水平。
A3 背景知识与关键观察
2.1 LLM训练的特点
-
复杂的并行策略:分布式LLM训练利用了多种并行策略,包括数据并行(DP)【48,PyTorch Distributed: Experiences on Accelerating Data Parallel Training,2020,arXiv preprint arXiv:2006.15704】、张量并行(TP)【68,Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism,2019,arXiv preprint arXiv:1909.08053】、流水线并行(PP)【38,GPipe: Efficient Training of Giant Neural Networks using Pipeline Parallelism,2019,Advances in Neural Information Processing Systems】、【54,PipeDream: Generalized Pipeline Parallelism for DNN Training,2019,SOSP ’19】、【55,Efficient Large-Scale Language Model Training on GPU Clusters Using Megatron-LM,2021,SC ’21】、【62,Zero Bubble (Almost) Pipeline Parallelism,2024,The Twelfth International Conference on Learning Representations】和序列并行(SP)【39,Deepspeed Ulysses: System Optimizations for Enabling Training of Extreme Long Sequence Transformer Models,2023,arXiv preprint arXiv:2309.14509】、【50,Ring attention with blockwise transformers for near-infinite context,2023,arXiv preprint arXiv:2310.01889】。为了优化GPU内存,通常会集成梯度检查点【12,Training Deep Nets with Sublinear Memory Cost,2016,arXiv preprint arXiv:1604.06174】和CPU卸载【64,Zero-Offload: Democratizing Billion-Scale Model Training,2021,USENIX ATC 21】。Adam优化器【43,Adam: A Method for Stochastic Optimization,2014,arXiv preprint arXiv:1412.6980】消耗的GPU内存是模型权重的6倍,因此采用Zero Redundancy Optimizer(ZeRO)【63,Zero: Memory Optimizations Toward Training Trillion Parameter Models,2020,SC20】通过分片优化器状态(ZeRO-1)、梯度(ZeRO-2)和模型参数(ZeRO-3)来减少内存占用。
-
多阶段配置调整:与使用单一固定配置和不变用户代码的传统DL作业不同,LLM预训练分为多个阶段,每个阶段都需要算法范式和系统优化的转变。如图1所示,一个典型的五阶段LLM预训练流程包括:
- 预热阶段 (Warmup Stage):小规模纯文本预训练,DP规模较小,用于验证算法变更和确保稳定性。
- 通用阶段 (General Stage):在广泛的文本语料库上进行全规模预训练,工程代码被迭代优化以获得最佳吞吐量和内存效率。
- 增强阶段 (Enhance Stage):重新加权数据混合以增强特定能力,例如高质量的STEM、编码和数学数据集以提高推理能力,或多模态语料库以实现跨模态理解。
- 长上下文阶段 (Long Context Stage):逐步扩展上下文窗口和分配的机器,并集成针对特定场景的工程代码,如混合数据并行(HDP)【27,ByteScale: Efficient Scaling of LLM Training with a 2048K Context Length on More Than 12,000 GPUs,2025,arXiv preprint arXiv:2502.21231】。
- 可选的退火阶段 (Anneal Stage):对某些领域特定或合成数据集进行精细的欠采样,以调整和稳定最终性能。
图1. LLM预训练的流程。TextPT:文本预训练;MMCT:多模态混合持续训练;ReasonCT:推理持续训练;LongCT:长上下文持续训练;AnnealCT:退火持续训练。不同的LLM可能会重新排序这些阶段【19,The Llama 3 Herd of Models,2024,arXiv preprint arXiv:2407.21783】、【74,Kimi K2: Open Agentic Intelligence,2025,arXiv preprint】。 -
频繁的故障和重启:大规模LLM训练常因频繁的故障和重启而中断。图2展示了一个在1000个GPU上运行10天的LLM训练任务的损失和模型FLOPs利用率(MFU)曲线。在此期间,共进行了28次运行(每次对应一次模型训练的重启)。中断原因包括基础设施问题以及对训练算法和策略的手动调整。随着训练的进行,损失逐渐下降而MFU增加,反映了工程优化的效果。值得注意的是,手动重启时,训练进度可能会被有意回滚几步,以验证工程改进的正确性并确保损失曲线的比特级一致。
图2. 在生产环境中,一个在1000个GPU上运行的LLM训练作业的归一化损失和相对MFU(与最小MFU值的比率)曲线。每种颜色表示一个连续、不间断的训练周期。
2.2 训练事件观察
-
事件分布:表1总结了在生产平台上三个月内捕获的所有LLM训练作业的训练事件。这些事件分为三类:
- 显式故障 (Explicit failures):具有明确诊断指标,如stdout/stderr日志中的错误消息或特定的退出码。
- 隐式故障 (Implicit failures):表现为作业挂起、性能下降或训练轨迹异常,其根本原因通常难以捉摸。
- 手动重启 (Manual restart):为改进算法和工程而主动中断训练。例如,持续集成内核融合【10,FLUX: Fast Software-Based Communication Overlap on GPUs Through Kernel Fusion,2024,CoRR abs/2406.06858】、计算通信重叠【11,Centauri: Enabling Efficient Scheduling for Communication-Computation Overlap in Large Model Training via Communication Partitioning,2024,ASPLOS ’24】等优化技术。
Table 1. 过去三个月收集的训练事件统计数据,涵盖778,135个LLM训练作业。
-
不同的非生产性时间:图3显示了由训练事件引起的非生产性时间分解,包括检测、定位和故障切换时间。
- 显式故障:检测时间短(约60秒),定位时间在2到15分钟之间。
- 隐式故障:难以检测和定位。例如,一个由CUDA错误引起的通信挂起问题,手动诊断耗时超过一个半小时。GPU硬件上的静默数据损坏(SDC)【14,Silent Data Corruptions at Scale,2021,arXiv preprint arXiv:2102.11245】、【19,The Llama 3 Herd of Models,2024,arXiv preprint arXiv:2407.21783】、【35,Cores that don’t count,2021,HotOS ’21】、【52,Understanding Silent Data Corruption in LLM Training,2025,arXiv:2502.12340】表现为随机故障,如突发的损失发散或NaN值,难以在停机诊断中复现。一个依赖于数据类型的计算错误源于GPU SDC,经过8个多小时的离线压力测试才定位到故障GPU。
- 手动重启:非生产性时间仅包括故障切换时间。
图3. 故障发生时的非生产性时间分解。以作业挂起等隐式故障为例,因为它们通常导致更长的非生产性时间。
2.3 实现高ETTR的挑战
-
复杂的故障根本原因:相同症状下的故障根本原因可能涉及不同方面。表2总结了大规模训练作业(>2000 GPU)在一个月内的事件,分为基础设施和用户代码两大类。例如,作业挂起可能是由NVIDIA IB交换机UFM故障(基础设施问题)或检查点重分片配置错误(用户代码问题)引起的。GPU内存错误(如非法内存访问)可能源于损坏的HBM(基础设施)或计算内核实现不当(用户代码)。NaN值可能来自问题数据、代码错误或硬件引起的SDC。用户代码的演进进一步加剧了故障定位的难度。
Table 2. 事件的根本原因
-
隐式故障难以检测和定位:根据表1,挂起(Hang)是隐式故障的典型指标,占所有事件的10%以上。现有系统依赖日志分析,但在挂起时,直到超时(例如NCCL的30或60分钟)才会产生任何日志。MegaScale【42,MegaScale: Scaling Large Language Model Training to More Than 10,000 GPUs,2024,NSDI 24】利用RDMA流量监控可以更早发现异常,但定位根本原因仍然困难。此外,SDC问题因分布式LLM训练中的集体通信范式而加剧,单个损坏的梯度会污染所有工作节点的全局参数更新,从而掩盖了原始故障位置。
-
故障切换的不确定性和高开销:故障切换操作包括调度新机器、重建pod环境、从远程存储加载最新检查点以及重新计算丢失的训练进度。这个过程可能引入新的降级机器,并产生歧义(新故障是由新代码还是基础设施引起)。故障切换本身开销巨大,例如从低带宽前端网络检索检查点耗时较长,并且由于检查点间隔较大(例如30分钟),导致大量的重算开销。在万卡规模的训练中,故障切换的耗时通常超过10分钟。
A2 方法细节
3. ByteRobust 概览
ByteRobust架构。ByteRobust旨在通过自动诊断和处理各种训练事件,同时最小化非生产性时间,以实现高ETTR。如图4所示,ByteRobust由控制平面和数据平面两个核心组件构成。控制平面在训练作业外部运行,负责协调鲁棒的事件处理策略,包括异常检测、故障定位和触发恢复动作。数据平面驻留在每个训练pod内部,集成了监控、诊断、检查点管理和堆栈跟踪捕获等模块,为实时可观察性、中断时的即时诊断、快速检查点回滚和按需聚合分析提供支持。
图4. ByteRobust的架构。
-
控制平面(Control Plane):该平面包含两个模块,用于实现LLM训练中的鲁棒故障检测、定位和恢复。
- 鲁棒控制器(Robust Controller):协调一个自动化的故障缓解框架(第4节),利用实时监控和停机诊断处理大多数事件。为了实现受控和快速的恢复,当没有机器被驱逐时,它使用原地热更新机制重启训练(第6.1节);当决定驱逐某些机器时,它会请求通过自检预先验证的温备机来恢复作业(第6.2节)。
- 运行时分析器(Runtime Analyzer):通过聚合来自训练pod的堆栈跟踪来解决作业挂起和性能下降问题,以隔离和(过度)驱逐可疑机器(第5节)。
-
数据平面(Data Plane):鲁棒代理(Robust Agent)守护进程在每个训练pod中运行,处理来自鲁棒控制器的控制信号,并管理以下四个子模块:
- 监视器(Monitor):收集多方面数据以检测异常值,支持实时检查(第4.1节)并在异常时触发聚合分析。
- 诊断器(Diagnoser):在作业暂停后运行领域特定的基准测试和测试套件【89,SuperBench: Improving Cloud AI Infrastructure Reliability with Proactive Validation,2024,USENIX ATC 24】、【91,Simple Testing Can Prevent Most Critical Failures: An Analysis of Production Failures in Distributed Data-Intensive Systems,2014,OSDI 14】,从而对复杂故障进行深入诊断(第4.2节)。
- 按需追踪器(On-Demand Tracer):从训练进程中捕获堆栈跟踪(当调用聚合分析时),并将其上传到运行时分析器。
- CKPT管理器(CKPT manager):执行异步检查点操作,并将备份跨并行组存储到CPU内存和本地磁盘,以最小化恢复成本(第6.3节)。
4. 自动化容错
自动化容错框架。自动化容错对于扩展LLM训练至关重要,它通过最少的人工干预来检测、定位和解决事件,从而显著减少非生产性时间。考虑到GPU周期是训练集群中最昂贵的资源,快速、粗粒度的故障隔离通常比昂贵、细粒度的根本原因定位在诊断覆盖范围和效率之间取得了更好的权衡。为此,我们提出了一个自动化容错框架(图5),该框架结合了用于即时检测常见错误的实时检查、用于深入分析复杂故障的停机诊断、用于从瞬时故障中恢复的原地重试、用于从有缺陷的用户代码中恢复的代码回滚,以及用于解决如SDC等极端情况的回放测试。
图5. ByteRobust的自动化容错机制。
4.1 主动实时检查
-
系统巡检。监视器采用巡检线程,以预定义的秒级间隔执行一系列轻量级的系统健康状态查询。这些巡检对GPU无工作负载,对正在进行的训练作业是透明的。巡检主要涵盖:(i) 网络侧项目,如NIC掉线或抖动、丢包率、交换机掉线;(ii) GPU侧项目,包括DCGM服务状态【75,NVIDIA DCGM,2021,https://developer.nvidia.com/dcgm】、PCIe带宽、内存行重映射【76 ,NVIDIA GPU Memory Error Management,2022,https://docs.nvidia.com/deploy/a100-gpu-mem-error-mgmt/index.html#row-mapping】和GPU温度等 ;(iii) 主机侧项目,如操作系统内核事件(例如dmesg中的Xid【57,Xid Errors,2024,https://docs.nvidia.com/deploy/xid-errors/】)。我们为这些项目设置了不同的巡检间隔和触发阈值,以容忍自动恢复。一旦检测到任何异常(步骤①),监视器将警告事件报告给鲁棒代理,后者再通知鲁棒控制器。对于指向特定机器的高置信度事件,如GPU不可用、磁盘故障,控制器会立即停止所有进程并驱逐有问题的机器,跳过停机诊断(第4.2节)。对于网络问题,控制器会容忍几次警报(经验上为5分钟内两次),因为其中一些问题(如NIC和网络交换机翻转)可以自动恢复【15 ,Boosting Large-Scale Parallel Training Efficiency with C4: A Communication-Driven Approach,2024,CoRR abs/2406.04594】。如果在机器驱逐后重启训练再次失败,ByteRobust将进入停机检查程序。
-
指标收集。监视器还根据三类数据收集各种指标:(i) 特定于工作负载的训练指标,包括损失、梯度范数、MFU等。我们利用wandb【81,AI is Easy to Productionize,2025,https://wandb.ai/site/】收集这些持续可观察的指标,并将它们的显著变化视为故障信号,例如损失/梯度范数增加5倍、NaN值 。(ii) stdout/stderr日志和进程退出码,作为诊断的线索。(iii) 事件,包括CUDA、RDMA、主机和存储事件。这些事件对于推导系统性能指标(如RDMA流量和TensorCore利用率)至关重要。鉴于LLM训练的周期性,这些指标的显著下降可作为潜在作业挂起和MFU下降的信号。在运行时,控制器分析收集的指标。如果检测到用户空间错误,例如可从日志和退出码追溯到特定代码模块的TypeError、IndexError,它会触发代码回滚(步骤②)。如果训练崩溃或出现异常指标(如NaN损失)而没有明确的罪魁祸首,它会暂停训练并运行停机检查(步骤③)。当发现性能异常时,例如10分钟内RDMA流量为零或TensorCore利用率低,会触发聚合分析以进行机器隔离(第5节)。
4.2 分层停机检查
-
分层停机检查机制。尽管主动实时检查可以利用巡检将大多数显式故障与故障机器联系起来,但仍存在一些仅凭实时收集的信息难以解决的错误。ByteRobust考虑了潜在的人为错误,并进行分层的停机检查来处理这些情况。
-
诊断 (Diagnose)。诊断器分析日志和退出码进行故障诊断,运行相应的测试以定位根本原因。例如,当出现NCCL内部错误时,会进行NCCL测试:首先运行NVIDIA扩展实用程序诊断(EUD)【56,Extended Utility Diagnostics (EUD),2024,https://docs.nvidia.com/datacenter/dcgm/latest/user-guide/dcgm-eud.html】以确认GPU是否存在明显错误。如果没有,则运行机内all-to-all测试,验证GPU间连接带宽是否符合预期。如果机内测试通过,则进行机间通信测试。每台机器与相邻机器运行all-gather测试,以验证连接性和数据传输的完整性。发现的可疑机器将被驱逐,其IP地址被阻止(步骤④)。之后,唤醒温备机以重启训练(第6.2节) 。
-
重试 (Reattempt)。如果所有测试都通过,诊断器会假设故障是由瞬时故障引起的,如临时链路抖动、交换机掉线、连接重置等。然后直接重启训练作业(步骤⑤)。
-
回滚 (Rollback)。当重启训练未能解决问题(步骤⑥)或在机器驱逐后训练再次崩溃(步骤⑦)时,诊断器会假设最近的用户代码更新风险很高。然后,它会使用热更新机制(第6.1节)回滚用户代码,移除集成的新功能(例如新融合的计算内核),并重启训练。如果训练成功重启,则用户代码被视为根本原因。相关团队将被邀请检查其代码的可靠性,同时训练继续进行。
-
双阶段回放 (Dual-Phase Replay)。如果训练仍然失败,ByteRobust会假设存在未知故障(例如SDC),并采用受控环境下的分组测试进行定位。对于大规模3D并行训练【55,Efficient Large-Scale Language Model Training on GPU Clusters Using Megatron-LM,2021,SC ’21】,机器压力测试和基准测试【89,SuperBench: Improving Cloud AI Infrastructure Reliability with Proactive Validation,2024,USENIX ATC 24】会破坏当前LLM作业的原始计算-通信模式和数据依赖性,从而影响复现性。为保持诊断保真度,我们引入了一种双阶段、维度感知的回放方法,该方法在保持原始TP/PP大小固定的同时,仅改变DP大小(步骤⑧)。算法1详细说明了定位过程。我们将机器划分为水平和垂直组,减少模型层数,并以减小的DP大小在每组上回放作业(第2-8行)。故障水平组和垂直组的交集精确定位了故障机器(第9-11行),然后将其驱逐(步骤⑨)。在实践中,我们设置 $k = n \cdot \text{PP\_size}$,$m = \text{DP\_size} / n$,其中 $n \in \mathbb{N}^+$ 且 $n \le m$ 以获得唯一解。由于 $\text{PP\_size} \ll \text{DP\_size}$,组内通信仍然具有代表性。如图6所示的例子,通过两次回放训练作业并在每个阶段识别故障组,SDC机器 #13被正确定位。这种设计选择有效地减少了非生产性时间,而无需依赖高级诊断工具。根据我们的经验,每个SDC事件通常只涉及单个故障机器,这在大规模训练中是常见情况。
Algorithm 1: Dual-Phase Replay
图6. 运行算法1识别SDC机器的示例,其中 $n = 4, m = 6$。$H_i$ 表示水平分组阶段的组 $i$,而 $V_j$ 表示垂直分组阶段的组 $j$。
- 经验教训:简单方法解决大多数事件。基于对19个大规模LLM训练作业(≥ 9,600个GPU)的经验观察,我们发现通过实时检查直接驱逐机器解决了32.52%的故障,重试恢复了22.70%,回滚处理了另外9.20%。只有1.23%的故障需要双阶段回放。
4.3 案例研究
- NaN损失诊断。在训练期间,当监视器检测到NaN损失时,首先会进行标准的GPU和网络测试,包括EUD和NCCL测试。如果所有这些测试都通过,则运行一个比特级对齐测试:每台机器启动一个参考模型,其结构与目标训练作业相匹配(例如,密集模型【7,Language models are few-shot learners,2020,Advances in neural information processing systems】或MoE模型【66,Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer,2017,arXiv preprint arXiv:1701.06538】)。它加载预定义的权重,采用特定的并行配置(例如,TP=2, PP=2, DP=2或EP=2, PP=2, DP=2),并在固定输入上执行一个训练步骤以确保可复现性。收集并分析所有机器的输出,以验证比特级准确性。产生不正确结果的机器会被迅速隔离和移除。如果此测试未识别出任何有缺陷的机器,则依次采用重试和回滚来解决潜在的瞬时故障和人为错误。如果训练仍然失败,则应用双阶段回放测试进行故障排除。
5. 数据驱动的过度驱逐
- 处理隐式故障的挑战。除了NaN值,隐式故障还表现为作业挂起和MFU下降(表1)。当作业挂起时,没有可追踪的信息被记录下来用于停机诊断。至于MFU下降,虽然任务变慢,但所有机器同时变慢,IO和RDMA等吞吐量都同时下降。所有这些因素都使得通过分析现有的外部信息来识别潜在的故障机器变得极其困难。为了克服这一挑战,ByteRobust在检测到这些静默故障时,会挂钩并检查所有内部训练进程的堆栈跟踪,以定位故障机器。当收到聚合触发消息时,控制器通知按需追踪器捕获进程堆栈跟踪,然后将其发送到运行时分析器在后台进行聚合分析。我们首先通过一个作业挂起的例子来介绍聚合分析机制,然后通过一个案例研究进行进一步说明。
5.1 聚合分析
-
通过堆栈聚合定位异常。为了精确定位异常位置,聚合分析会比较不同机器中GPU rank的调用堆栈。与事件、训练指标和stdout/stderr日志相比,进程的堆栈跟踪为处理复杂事件提供了丰富的信息源。然而,根本原因可能存在于主训练进程为数据获取或检查点等任务生成的子进程中【80,ByteCheckpoint: A Unified Checkpointing System for Large Foundation Model Development,2025,NSDI 25】;仅仅分析主训练进程的堆栈是不够的。ByteRobust采纳了这一观察,并执行三步聚合进行全面分析,其假设是大多数健康机器在单一隐式故障下表现出相同的堆栈跟踪。
-
三步聚合流程。图7展示了一个静默的后向通信挂起。在此例中,机器15(托管模型流水线的最后一个阶段,为后向传播生成激活梯度)在
all_gather_into_tensor中停滞。同时,与完成了所有后向相关内核启动并进入优化器中梯度同步的机器0-11不同,机器14和机器12-13在为某些微批次传输梯度时分别阻塞在isend和irecv。传统诊断方法难以高效精确地确定故障机器集合。相反,ByteRobust通过三步流程过度驱逐隔离的机器来解决此问题,避免了精确定位根本原因的需要。首先,ByteRobust解析每个训练pod中的进程树,以识别与训练相关的进程,例如torchrun、dataloader和检查点进程。其次,将这些已识别进程的堆栈跟踪通过字符串匹配聚合成多个组,以区分异常源。主导组被认为是健康的(图7中的绿色堆栈),而其余组被归类为异常值(其他颜色)。最后,我们找到这些异常值的共享并行组,并隔离相应的机器。在此例中,共享并行组是一个PP组(机器12, 13, 14, 15)。鲁棒控制器驱逐这些可疑机器,然后恢复训练。 -
处理慢速故障。对于慢速故障事件(即MFU下降),ByteRobust每10秒重复一次聚合,在每一轮中标记出异常值最多的并行组。在5轮中累积标记次数最多的并行组被标记为降级者,进行过度驱逐。
图7. 用于定位后向通信挂起的堆栈聚合。并行配置:TP=2, PP=4, DP=4。
5.2 案例研究
- 隐式故障案例分析。接下来,我们将深入探讨一个代表性的隐式故障以及聚合分析如何工作。
- 评估阶段挂起 (Evaluation hang)。我们在LLM评估步骤【34,Measuring Massive Multitask Language Understanding,2020,arXiv preprint arXiv:2009.03300】中遇到了任务挂起,该步骤通常用于衡量模型的多任务能力。在一个例子中,堆栈聚合分析隔离了一个跨越6台机器的特定流水线,其中中间阶段的堆栈与同一DP×TP组中其他rank的堆栈不同。因此,这些阶段卡在了它们的P2P通信操作中。这6台机器被自动列入黑名单并被驱逐,温备用实例被调度用于快速替换和重启训练。通过数天的后台压力测试,我们最终确定了根本原因:其中两台机器存在有缺陷的CUDA核心,导致挂起并阻止了P2P操作。
6. 受控且快速的恢复
- 恢复机制目标。在故障检测和定位之后,ByteRobust在一个一致的环境中快速重启训练,以最小化停机时间并避免新的故障。具体来说,我们应用原地热更新(第6.1节)进行代码/数据调整,使用温备机(第6.2节)消除调度成本,并采用感知过度驱逐的检查点机制(第6.3节)以实现快速快照和本地安全备份。
6.1 原地热更新
- 原地热更新机制。为代码调整而手动重启训练在LLM训练期间是常态。为代码升级或回滚重新调度新机器不仅会产生巨大开销,还可能引入有故障的机器,使重启后发生故障时的定位复杂化。为了最小化开销并避免在重启期间部署潜在故障机器的风险,我们引入了一种惰性热更新机制,用于在不破坏现有pod环境的情况下进行原地代码修改。更新策略根据代码修改的性质量身定制。对于像bug修复这样的紧急请求,会立即停止训练以应用更新。对于不太关键的更改,如试验新的优化或更新软件版本,更新会在下一次故障发生时集成到恢复过程中,利用在大规模LLM训练中观察到的频繁中断(例如,Llama 3.1训练期间平均每2.78小时发生一次中断【19,The Llama 3 Herd of Models,2024,arXiv preprint arXiv:2407.21783】)。在任何情况下,当默认触发窗口(例如24小时)到期时,未应用的非关键更新将被执行。所有修改都将持久化在我们的数据库中,使其可追溯和可复现。热更新机制还通过自动应用和回滚(第8.1.2节),使不断演进的训练代码的持续集成成为鲁棒LLM训练流水线的一部分。
6.2 温备机
-
温备机机制。每当发生机器驱逐时,ByteRobust会利用温备用实例快速替换缺失的机器以恢复训练。尽管在备用机器上会引入一些GPU空闲,但减少的重启成本转化为集群中健康机器利用率的提升,尤其是在大规模训练期间高频训练中断的情况下【19,The Llama 3 Herd of Models,2024,arXiv preprint arXiv:2407.21783】。我们维护一个备用机器池,并根据关键观察——大规模训练中的故障通常是独立的,发生在单个节点上,涉及多个节点的并发故障极为罕见【31,Just-In-Time Checkpointing: Low Cost Error Recovery from Deep Learning Training Failures,2024,EuroSys】、【94,OPT: Open Pre-Trained Transformer Language Models,2022,arXiv preprint arXiv:2205.01068】,来决定备用机器的数量。我们使用历史数据估计单台机器的日故障率,并通过二项分布对机器间的并发故障进行建模。我们将温备用实例的数量设置为该分布的第99百分位数(P99),这在大多数场景下能有效满足需求。
-
动态补充与激活。备用机器池是动态补充的。在每个新的备用机器上执行Pod环境初始化,包括机器自检以确保其健康状态、镜像安装和库下载,然后进入低功耗睡眠模式。当发生机器驱逐时,如果有足够的备用机器,它们会被直接唤醒并集成到训练中;否则,会立即进行补充,并在所有所需机器完成其Pod环境初始化后重启训练。这种设计的另一个好处是,在发生故障和随后的作业重启事件中,只有最少数量的机器发生变化;其余的机器完全像以前一样继续运行,从而提高了资源效率和模型训练的可控性。
6.3 感知过度驱逐的检查点
-
内存中检查点机制。ByteRobust倡导在内存中进行检查点,通过在本地和对等机器上保存和备份检查点。它采用一种分层检查点方案,利用主机CPU内存和SSD存储层,并结合一种能预见机器过度驱逐(第5节)的备份策略来保证可用性。通过消除对低带宽前端网络上的远程存储服务的依赖【20,Check-N-Run: A Checkpointing System for Training Deep Learning Recommendation Models,2022,NSDI 22】、【80,ByteCheckpoint: A Unified Checkpointing System for Large Foundation Model Development,2025,NSDI 25】,ByteRobust避免了由存储服务故障引起的潜在训练挂起或崩溃(见表1,其中我们有1104个HDFS错误)。
-
操作调度。通过精细的操作调度,ByteRobust实现了近乎零开销的内存中检查点。如图8所示,为了备份分片的模型和优化器状态,ByteRobust利用了每个训练步骤中的空闲通信周期,即在前向和后向计算期间,并采用P2P通信让每个rank与其在选定备份机器中的对等rank交换这些分片(备份策略详见下文)。这些备份分片随后被保存到CPU内存中。检查点I/O操作以前向和后向计算异步的方式执行。GPU计算的优化器步骤等待每个rank自身检查点保存完成,以确保数据完整性。备份检查点可以与模型和优化器更新并发保存。ByteRobust创建一个独立的CUDA流来隔离与训练相关和与检查点相关的内核的执行。对于与前向和后向传播并行执行的备份通信,我们将状态划分为小块,将传输与不同并行维度的训练通信流量交错进行。
图8. 使用ZeRO风格并行进行检查点和备份操作调度的示例。
- 跨并行组备份策略。在机器间复制分片的优化器和模型状态对于容忍机器故障至关重要。在ByteRobust中,机器的过度驱逐主要源于聚合分析(第5节),其中整个并行组可能被驱逐以实现快速的训练重启。因此,选择目标机器来安全存储备份至关重要。ByteRobust倡导一种跨并行组的备份策略来应对潜在的机器过度驱逐。如图9所示,在进行大规模3D并行训练时,每个rank将其分片的优化器状态备份到其3D并行组之外。例如,rank 8和9与rank 2和3交换它们的优化器状态,确保没有一个共享相同的PP、DP或TP组。同样,在DP组内去重的分片模型状态【80,ByteCheckpoint: A Unified Checkpointing System for Large Foundation Model Development,2025,NSDI 25】,也遵循此备份策略。如果并行策略仅包含单个并行组(例如,ZeRO并行),系统默认在相邻机器中进行备份。
图9. 具有过度驱逐感知的检查点备份。3D并行配置:TP=2, PP=4, DP=2。
7. 实现
-
鲁棒控制器和代理 (Robust Controller and Agent)。鲁棒控制器由一个编排模块和一个控制模块组成,用20k行Golang代码编写。我们使用Kubernetes自定义资源定义(CRDs)实现编排模块来表示作业操作(约3k LoC)。每个作业都有一个用于弹性训练规则的运行时CRD和一个用于pod调度的作业CRD。为了提高集群管理效率,我们用内部元数据系统替换了标准的etcd【21,etcd: Distributed Reliable Key-Value Store for the Most Critical Data of a Distributed System,2022,https://github.com/etcd-io/etcd】,并利用内部调度器进行pod组调度。控制模块围绕一个作业管理器服务,该服务维护作业控制器( 约17k LoC)。对于每个作业,我们向作业管理器注册一个专用的控制器服务,使用goroutine实现高效的资源共享、各种温备份策略和统一的故障恢复。鲁棒代理是一个Python守护进程(约5k LoC),与每个作业一起运行以管理训练进程。该代理通过基于gRPC的心跳与控制器通信,并支持运行时热更新。
-
运行时分析器 (Runtime Analyzer)。运行时分析器用大约12k行Golang代码实现。分析器通过将日志、I/O操作、主机异常、按需追踪器输出和pod异常聚合成统一事件来标准化异常。由于观测数据的异构性和分散性以及需要快速问题分类,我们设计了一个事件驱动系统进行实时分析。它允许快速定位根本原因,并与鲁棒控制器协作进行快速故障处理。对于NCCL超时问题,它从按需追踪器收集堆栈跟踪,该追踪器使用py-spy【5,py-spy,2019,https://github.com/benfred/py-spy】和flight-recorder【61 ,Flight Recorder for Debugging Stuck Jobs,2025,https://docs.pytorch.org/tutorials/unstable/flight_recorder_tutorial.html】实现,并收集训练拓扑信息以方便故障排除。分析器还构建了一个工作节点训练进程的进程树,以满足各种分析需求 。
-
温备机 (Warm Standby)。我们利用鲁棒控制器的编排模块,通过异步供应来维护指定数量的温备用节点。初始化时,每个鲁棒代理查询控制器以确定其状态,是温备用还是活动训练。当执行到达阻塞代码执行的预设屏障时,备用机器上的进程会验证其当前状态。如果它们处于备用状态,这些进程会进入一个轮询循环,定期向鲁棒控制器查询激活信号。一旦发出激活信号,训练将无缝地在屏障之后恢复,将温备用节点无中断地集成到正在进行的训练工作流中。
-
高频检查点 (High-Frequency Checkpointing)。高频检查点用3k行Python代码实现,带有一个用于CPU张量的双缓冲,它在不同迭代之间交替存储优化器的状态字典。我们通过重叠三个操作来实现异步检查点:设备到主机(D2H)复制、序列化和发送到其他rank进行备份。当第一个CPU张量正在进行D2H复制时,我们同时对第二个张量执行序列化或发送。D2H操作在专用的CUDA流上执行,使得D2H内存复制能够与训练计算独立执行。故障恢复通过根据D2H和序列化完成状态选择最新的可用检查点来实现。
A4 实验环境
- 硬件配置:所有实验均在生产GPU集群上进行。
- 生产部署实验 (8.1节):使用了多达1200台机器,每台配备8个NVIDIA Hopper 80GB GPU。
- 效率评估实验 (8.2节):使用了共1024台机器,每台配备16个NVIDIA L20 48GB GPU,通过30GB/s的PCIe连接,总计超过16,384个GPU。
- 通用配置:所有机器通过八个400 Gbps RDMA链路互连,搭载96核Intel Xeon处理器,并配备2TB DRAM。
- 软件配置:
- 语言与框架:ByteRobust核心组件使用Golang和Python实现。
- 依赖库与工具:
- 编排:使用Kubernetes自定义资源定义(CRDs),并替换etcd为内部元数据系统。
- 通信:控制器与代理之间使用gRPC。
- 诊断工具:使用py-spy【5,py-spy,2019,https://github.com/benfred/py-spy】和PyTorch的flight-recorder【61 ,Flight Recorder for Debugging Stuck Jobs,2025,https://docs.pytorch.org/tutorials/unstable/flight_recorder_tutorial.html】进行堆栈跟踪 。
- 监控与指标:使用wandb【81,AI is Easy to Productionize,2025,https://wandb.ai/site/】收集训练指标 。
- 模型与任务:
- 生产部署 (8.1节):对两个内部生产级模型进行预训练:一个为期三个月的密集模型(类Llama【19,The Llama 3 Herd of Models,2024,arXiv preprint arXiv:2407.21783】,70B+参数)和一个为期一个月的MoE模型【8,Doubao-1.5-pro,2025,https://seed.bytedance.com/en/special/doubao_1_5_pro/】(200B+参数),均在9,600 个Hopper GPU上运行。
- 效率评估 (8.2.2节):在稀疏MoE LLM(70B和256B模型大小)上评估检查点性能,采用3D并行与ZeRO-1。
A4 实验结果
8.1 生产环境中的鲁棒性
-
有效减少事件检测时间 (8.1.1):ByteRobust的实时检查机制通过为不同基础设施组件设置专门的检测频率和判断标准,显著减少了故障检测时间。如表3所示,对于网络组件,巡检间隔为30秒,连续两次无响应才报警;对于文件系统内核级错误,能即时检测;对于GPU高温,10秒内即可检测并关联MFU下降来验证灰色故障。相比之下,基线方法仅依赖超时(约30分钟)和多轮迭代后的性能指标报警,检测速度慢得多。
Table 3. 检测不同基础设施故障的时间。T_torchrun是PyTorchDistributed的默认超时阈值(约10分钟)。T_MFU是监控MFU下降的时间间隔。
-
高效解决各类事件 (8.1.2):表4展示了ByteRobust中不同机制在两个生产作业(密集模型和MoE模型)中解决事件的分布。
- 大部分显式故障通过自动化容错机制(AutoFT-ER,即机器驱逐+重启)解决,分别占73.1%和56.8%。
- 对于隐式故障(作业挂起和MFU下降),运行时分析器(Analyzer-ER)通过机器过度驱逐成功解决了24个事件,避免了人工干预。
- 代码回滚(Rollback)机制识别了多个工程代码问题,分别占6.9%和11.2%。
- 所有手动重启需求(代码和数据调整)均由热更新机制(AutoFT-HU)处理。
Table 4. 两个生产作业中不同机制解决事件的分布。数字代表事件计数,括号内为百分比。
-
保障训练性能 (8.1.3):
- ETTR:如图10所示,ByteRobust在两个作业中均将累计ETTR维持在高达97%的水平,并将非生产性训练时间控制在最长50分钟内。尽管在训练后期因引入长上下文新功能和集群老化导致故障频率增加(滑动窗口ETTR波动增大),但系统仍能高效地检测、诊断和恢复。
- MFU:如图11所示,随着训练的进行,两个作业的相对MFU持续增长。MFU曲线的每次跃升都表示通过ByteRobust的热更新部署了更高效的训练代码版本,而ETTR仅有微不足道的下降。最终,密集模型和MoE模型的MFU分别比初始运行时提高了1.25倍和1.58倍。
图10. 密集LLM和MoE预训练作业中的累计ETTR和滑动窗口ETTR。
图11. 密集LLM/MoE训练作业的相对MFU,为与各自最小MFU值的比率。 -
与传统实践的对比 (8.1.4):将ByteRobust的自动化容错框架与传统的选择性压力测试【36,Characterization of Large Language Model Development in the Datacenter,2024,NSDI 24】、【89,SuperBench: Improving Cloud AI Infrastructure Reliability with Proactive Validation,2024,USENIX ATC 24】进行比较。如表6所示,ByteRobust显著缩短了所有症状的平均解决时间,例如对CUDA错误的解决时间减少了84.5%。对于由人为错误引起的症状,基线的压力测试无法定位故障,而ByteRobust的回滚机制能够精确定位并恢复。
Table 6. 事件解决成本比较。
8.2 故障恢复效率
-
快速作业重启 (8.2.1):
- 高效热更新:在5次手动代码更改事件中,通过重用现有环境,ByteRobust的热更新机制比完全重新排队(requeue)快11.04倍(表7)。
- 高效温备机:在模拟不同规模的机器驱逐事件中(图12),ByteRobust的温备机方法将恢复时间相比requeue减少了10.87倍,相比仅替换故障机器的reschedule减少了5.36倍,并且与假设无限备用机的理想情况(oracle)相比仅慢5.19%。
- 可扩展性:随着训练规模扩大,requeue的重启时间显著增加,而ByteRobust的温备机和热更新开销保持恒定低水平,展示了卓越的可扩展性。
Table 7. 在5次代码更新事件中,requeue和热更新机制的调度时间比较。
图12. 机器驱逐事件下的加权平均调度(WAS)时间。
Table 5. 两个稀疏LLM训练作业的训练设置。Scale给出用于训练的机器数×GPU数。P99表示备份机器数×GPU数。Catastrophic表示极端故障情况(<1%概率)涉及的机器数×GPU数。
-
近乎零开销的检查点 (8.2.2):在稀疏MoE LLM上评估检查点性能。如表8所示,ByteRobust的检查点机制(ByteRobust save)通过将I/O与训练重叠,将阻塞时间(即检查点停顿)相比Megatron save和Gemini提出的Memory save分别减少了99.69%和95.10%。同时,MFU损失仅为0.71%,相比后两者分别改进了98.8%和89.6%。
Table 8. 检查点效率比较。MFU值为相对于无检查点训练MFU的相对值。
A7 补充细节
9. 经验与局限性
-
不成熟的诊断工具:GPU硬件发展迅速,但相关的监控和诊断工具往往滞后,使得故障根本原因分析充满挑战。为确保在这种约束下的鲁棒性,我们引入了系统级适应措施,包括应用级隔离策略,如数据驱动的过度驱逐和双阶段回放。这些技术在GPU集群新硬件的早期部署阶段尤其有价值。值得注意的是,诊断工具本身偶尔也会引入新的故障,例如我们曾观察到EUD诊断程序无意中解除了频率锁定,导致GPU意外降频,从而造成MFU下降。
-
假阳性(False Positive):假阳性主要来自两个来源:(i) 诊断工具的局限性:EUD或网络诊断等工具的不完善可能触发错误警报,导致不必要地驱逐和压力测试健康机器,对集群利用率影响较小。(ii) 有意的过度驱逐:为了在3D并行训练中加速故障定位,我们会驱逐整个流水线并行(PP)组(例如,在9600-GPU作业中每组8台机器),尽管通常只有1-2个节点是故障的。虽然这导致了6-7个假阳性,但考虑到训练作业通常涉及约10,000个GPU,且早期隔离能显著减少恢复时间,这种权衡是可以接受的。
-
静默数据损坏(Silent Data Corruption, SDC):SDC是扩展LLM训练规模时一个关键但常被忽视的挑战。SDC由输入敏感的数值不稳定性、竞争条件和热变化等因素引起,导致不正确的计算,如NaN值或梯度异常【19,The Llama 3 Herd of Models,2024,arXiv preprint arXiv:2407.21783】、【35,Cores that don’t count,2021,HotOS ’21】。分布式训练中的集体通信模式加剧了这些错误的传播。在我们的生产环境中,NVIDIA的EUD诊断工具【56,Extended Utility Diagnostics (EUD),2024,https://docs.nvidia.com/datacenter/dcgm/latest/user-guide/dcgm-eud.html】的召回率仅为70%。为缓解此问题,我们开发了MiniGPT验证套件,使用确定性工作负载进行机内验证,并使用双阶段回放测试进行机间故障复现。然而,这些方法开销巨大,并且随着训练规模的增加,SDC的频率和影响也在增加,这凸显了对更高效的检测、隔离和诊断技术的需求 。
10. 相关工作
-
容错LLM训练:Megascale【42,MegaScale: Scaling Large Language Model Training to More Than 10,000 GPUs,2024,NSDI 24】结合心跳和RDMA指标监控来检测故障,但检测到RDMA流量异常时无法自动隔离可疑机器,需要人工调查。Hu等人【36,Characterization of Large Language Model Development in the Datacenter,2024,NSDI 24】的工作依赖日志数据,未利用运行时信息,而运行时数据能更快更准地识别隐式故障。这些系统虽有异步检查点,但未提供如ByteRobust的感知过度驱逐的备份策略。
-
弹性和韧性训练:一些工作【3,Varuna: Scalable, Low-Cost Training of Massive Deep Learning Models,2022,EuroSys ’22】、【18,Parcae: Proactive, LiveputOptimized DNN Training on Preemptible Instances,2024,NSDI 24】、【25,ReCycle: Resilient Training of Large DNNs using Pipeline Adaptation,2024,SOSP】、【40,Oobleck: Resilient Distributed Training of Large Models Using Pipeline Templates,2023,SOSP】、【47,EasyScale: Elastic Training with Consistent Accuracy and Improved Utilization on GPUs,2023,SC】、【78,Bamboo: Making Preemptible Instances Resilient for Affordable Training of Large DNNs,2023,NSDI 23】、【79,Tenplex: Dynamic Parallelism for Deep Learning using Parallelizable Tensor Collections,2024,SOSP】致力于增强训练的弹性和韧性以防止中断,但这些方法通常受限于特定的并行策略(如DP、TP),而ByteRobust支持LLM训练中广泛流行的各种并行策略。
-
灰色故障和SDC:灰色故障【37,Gray Failure: The Achilles’ Heel of Cloud-Scale Systems,2017,HotOS ’17】在存储系统、数据中心网络和云服务中已有深入研究,但在LLM训练中的原因探讨较少。ByteRobust利用运行时堆栈聚类和粗粒度隔离来快速缓解潜在的灰色故障。SDC是另一类难以检测的故障,近期研究主要关注其在CPU工作负载中的影响【14,Silent Data Corruptions at Scale,2021,arXiv preprint arXiv:2102.11245】、【35,Cores that don’t count,2021,HotOS ’21】、【82,Understanding Silent Data Corruptions in a Large Production CPU Population,2023,SOSP ’23】。我们观察到SDC也严重影响GPU集群上的大规模LLM训练,其症状与数据错误或工程bug重叠,且不确定性能否复现,导致诊断和解决时间过长,最终限制了LLM训练的可扩展性。
-
检查点:现有工作如Check-N-Run【20,Check-N-Run: A Checkpointing System for Training Deep Learning Recommendation Models,2022,NSDI 22】(差分检查点)、CheckFreq【53,CheckFreq: Frequent, Fine-Grained DNN Checkpointing,2021,FAST 21】(流水线化保存)、Gemini【84,Gemini: Fast Failure Recovery in Distributed Training with In-Memory Checkpoints,2023,SOSP】(内存中检查点和机间备份)和ByteCheckpoint【80,ByteCheckpoint: A Unified Checkpointing System for Large Foundation Model Development,2025,NSDI 25】(统一并行无关的表示)在检查点方面做出了贡献。ByteRobust在此基础上更进一步,将检查点与细粒度调度和感知驱逐策略的备份相结合。
A5 结论
本文介绍了ByteRobust,一个部署在字节跳动GPU集群中的LLM训练管理系统。基于大规模LLM训练的丰富经验,ByteRobust将故障特征、诊断能力和LLM特定功能整合到一个全面的系统设计中。它采用了一个自动化容错框架,能有效地区分故障类型,并使用运行时状态分析和数据驱动方法来检测和隔离故障机器。我们引入了高效的故障切换机制,包括聚合式热更新、温备机和故障感知检查点,从而最大限度地减少了停机时间。我们的见解旨在激发进一步的研究,并增强LLM训练系统的可靠性。
💬 评论讨论
欢迎在这里分享您的想法和见解!