百度百舸万卡集群的训练稳定性系统设计和实践

摘要

2012 年 ImageNet 竞赛中 AlexNet 的横空出世, 开启了现代 AI 发展的新纪元。彼时我们不会想到, 十年后支撑 AI 训练的 GPU 集群会从研究室里的几台服务器, 发展成需要专门供电系统的万卡级计算矩阵。在这个算力爆发式增长的过程中,训练系统的稳定性管理正经历着从「简单运维」到「精密工程」的深刻变革。

1. AI 训练稳定性的演进历程

2012 年 ImageNet 竞赛中 AlexNet 的横空出世, 开启了现代 AI 发展的新纪元。彼时我们不会想到, 十年后支撑 AI 训练的 GPU 集群会从研究室里的几台服务器, 发展成需要专门供电系统的万卡级计算矩阵。在这个算力爆发式增长的过程中,训练系统的稳定性管理正经历着从「简单运维」到「精密工程」的深刻变革。

1.1 早期的小模型时代:手动运维的黄金年代

2022 年之前的 AI 训练, 更像是手工作坊式的精雕细琢。大多数训练任务只需十几块 GPU, 利用 PyTorch 或 TensorFlow 的数据并行功能就能轻松应对。记得那时算法工程师们有个共识:如果训练遇到问题, 重启往往比排查更高效。

当时我们构建的监控系统就像汽车仪表盘, 只能显示最基本的任务状态。当训练意外中断时, 工程师们会像侦探一样翻查日志——如果发现是 GPU 报错, 就联系运维同事。运维人员则带着「NVIDIA 三件套」(nvidia-smi、dcgm、nsys) 到机房巡检, 像老中医把脉般通过温度、功耗等指标判断硬件状态。这种工作模式虽简单, 但应对数十卡规模的集群还算游刃有余。

1.2 大模型风暴:从量变到质变的冲击

ChatGPT 的登场如同打开潘多拉魔盒, 将 AI 训练带入新的纪元。当我们开始部署千卡/万卡集群时, 才发现原有的运维体系就像用小渔网捕鲸鱼——完全无法匹配新需求。

让我们通过百度百舸经历过的一个真实案例来深入理解这个问题:

2024 年初, 百度百舸帮助一家 AIGC 创业公司迅速将其训练规模从百卡扩展到千卡级别。然而在训练数天后的某个周末凌晨, 训练进程意外发生了 hang 死。由于当时缺乏有效的故障感知和容错机制, 直到第二天算法工程师发现任务超时退出时, 已经耽误了数小时宝贵的训练时间。更糟糕的是, 任务日志中除了简单的 timeout 报错外毫无线索, 平台监控也显示所有训练节点状态正常。着急恢复训练的算法工程师没有立即上报问题, 而是选择直接重新提交任务。但不幸的是, 新任务运行数小时后再次出现相同的超时退出。这时他们才不得不寻求技术支持, 但值班工程师面对这种任务 hang 死的问题也缺乏诊断经验, 只能通过二分法慢慢定位。最终发现是某个节点的静默故障 (SDC) 导致了训练进程假死。等问题得到解决时, 距离首次故障已经过去将近 30 小时, 这意味着损失了价值巨大的千卡算力资源。

2. 百度百舸集群训练稳定性全景图

站在现在的时间点回望,AI 训练稳定性已从辅助功能演变为核心基础设施。就像现代建筑中的抗震结构, 它虽不直接参与空间构成, 却是万丈高楼得以屹立的关键。当行业向着数万卡集群迈进时, 这套隐形护甲的质量, 将直接决定 AI 进化的速度与边界。

在 2024 年百度百舸对训练过程的生命周期进行了更细致的拆分, 提出了「无效训练时间」这一关键指标, 并致力于将其最小化。具体来说:

任务无效训练时间 = 故障中断次数 × 任务故障恢复时长 + 任务常态写 Ckpt 总时长

其中, 任务故障恢复时长 = 故障感知召回耗时 (自动/人工定位)+ 任务调度耗时 + 任务初始化耗时 + 任务重算时长。

通过这个公式可以看出, 要降低无效训练时间, 需要「围绕基础设施稳定性」、「任务容错」两个维度来系统展开, 重点解决三个方面的问题:

提高基础设施的交付质量。

提高任务故障容错的召回率、准确率和时效性。

优化 checkpoint 机制, 减少保存时间和恢复时的重算时间。

经过容错架构的整体变革, 百度百舸形成了从 「任务负载— 框架— 通信  基础架构」全链路的自动异常感知、诊断、恢复能力, 可覆盖 90%+ 的训练异常场景, 时效性最快可以实现秒级异常感知、分钟级定位, 以及平均 3 分钟的故障自愈能力。

3.    基础设施交付质量保障

基础设施的交付质量保障是稳定性的基础。

CPU 时代, 机器的交付前可能仅会跑一些常规的 CPU 计算、网络的压力测试, 并不会从业务视角去评估基础架构, 机器交付后硬件异常的故障频率相对较少。有硬件故障时, 通常走工单系统人工换机用户相对是可接受的。

而 GPU 时代,AI Infra 的交付则需要考虑 CPU、GPU、RDMA 网络、存储, 甚至机房的功率、温度等各方面因素, 遗漏任何一个环节都会成为后续稳定性的隐患。在交付给客户后, 机器也可能会由于长时间的高负载运行频繁出现硬件故障, 而 GPU 机器的高昂成本, 使客户对节点故障感知、换机的时效性提出了非常高的要求。

因此百度百舸对 GPU 机器交付前及交付后的稳定性质量进行了系统性管理:

交付前, 百度百舸会对机器进行 200 多项指标检测, 然后进行 48 小时烤机, 以及 NCCL-Test 的机内、机间的大环、同号卡通信性能基准测试, 端到端的大模型训练、推理性能基准测试。

交付后, 需要能够实时的感知节点故障及定期巡检, 并具备分级处理的自愈能力, 例如 Error 级别的故障实现自动排水、重启,Fault 级别故障实现自动换机。

4.    任务容错的准召率保障

任务层面稳定性最核心的就是做好容错, 能够让业务在无论遇到何种故障时都能快速恢复。那么, 首要的工作就是我们能够准确的识别出异常, 然后对故障进行诊断定位, 最后能够自动化的从异常中恢复。因此, 任务容错需要能够从端侧 (即每个训练 worker) 探测到进程与环境的各类异常, 同时有个中心服务 (Master) 从任务全局的视角去诊断、定位异常, 最终做出相应的决策来使任务能够快速从异常中恢复。

任务容错最重要的就是提升故障的召回率与准确率, 即如何能够尽可能的准确识别、定位所有故障。我们将故障分类两类:故障和隐式故障。

显式的故障通常比较容易召回, 我们将实践积累的各种进程异常状态及各类报错 pattern 形成专家知识库, 再结合硬件感知服务 (HAS Agent) 的硬件全链路 10 秒级监控能力, 可以实现显式故障的召回率达到 95%+。

隐式的异常则往往很难轻易的识别, 例如训练进程 hang、慢节点就是典型的隐式故障, 需要丰富的经验积累才能准确的识别出异常。

下面我们就以最典型的隐式故障场景——训练进程 hang 死为例, 来看下如何能够做好 hang 自动感知、诊断。

4.1.    训练 hang 的自动感知

训练任务发⽣ hang 之后, 绝⼤多数情况都会以 timeout 的⽅式报错并退出进程, 最常⻅的就是在通信过程中如果发⽣ hang,NCCL 的 watchdog 会中断通信, 并有报如下 timeout 报错, 然后再由 pytorch 的 torchrun 进程感知并中断训练过程。

[E ProcessGroupNCCL.cpp:828] [Rank 1] Watchdog caught collective operation timeout: WorkNCCL(SeqNum=15173, OpType=ALLREDUCE, Timeout(ms)=1800000) ran for 1802710 milliseconds before timing out.

[E ProcessGroupNCCL.cpp:828] [Rank 0] Watchdog caught collective operation timeout: WorkNCCL(SeqNum=15173, OpType=ALLREDUCE, Timeout(ms)=1800000) ran for 1802713 milliseconds before timing out.

Pytorch 默认为 10 分钟 NCCL 通信超时, 而 Megatron-LM 为 30 分钟。在万卡规模训练场景中, 意味着一万张卡要至少浪费 30 分钟才能被发现。这个时效性是不可接受的。而且当 30 分钟超时后程序会立马退出, 很难有机会进行下一步定位, 需要一些时效性更高的感知机制, 并且在程序退出前获取一些有效信息供后续诊断分析。

很多公司、实验室在面对 hang 的问题时, 会在采用框架层插桩的方式来 trace 训练进程, 这种方式通常是比较直接且准确的, 但是有比较强的侵入性, 而且可能还会有一些性能开销。对于云厂商来说, 需要寻找对用户更透明、更无损的方式来感知、定位 hang 异常。

如何感知训练 hang, 以百度百舸的产品设计思路为例, 我们可以从以下几个方向去思考:

1. 训练进程 hang 的最直观表现是什么?

人工判断一个任务是否 hang 了, 最直接的方式就是看是否所有 worker 的任务日志一段时间内都不输出日志了, 所以 hang 自动感知的第一种方法就是采集所有 worker 的日志, 并判断所有 worker 日志中最后一行日志是否为 x 分钟前的 (x 小于 Pytorch 的通信超时时间, 例如 8 分钟), 如果是则基本可以判定为 hang。

2. 任务 hang 时进程有什么样的表现?

任务 hang 时, 可能进程的调用栈都不在发生变化, 进程的调用栈可以通过 py-spy/pystack 等工具进行探测, 所以我们可以用此类工具对所有训练任务进行一个定时采样, 当采集 n 个样本所有进程栈都没有变化时, 可以判定一次 hang, 这种方式通常可以将 hang 感知缩小至 3~5 分钟。

3. 任务 hang 时监控指标有哪些变化?

训练进程中的 CUDA 算子计算、集合通信操作通常都是在毫秒, 甚至微秒、纳秒内完成的, 当任务在正常迭代过程中发生了 hang, 我们常遇到的情况是所有 rank 的 RDMA 流量会降到 0, 而 GPU 的利用率为 100%、SM 利用率则在很低的水位。如果持续几分钟都是这种状态时, 意味着训练进程已经计算完成, 在等着集合通信完成, 这种情况下基本可以判定为 hang。

4. 是否能在通信库中更快的感知通信 hang?

通常单次集合通信操作都是在 ms 级的, 如果一次操作在 30 秒钟都没有完成, 那就可以判定为通信 hang 死了。百度自研的 BCCL 集合通信库层可以对每一次集合通信操作都进行打点, 来实现通信 hang 感知。

上述几种方法, 我们可以分别实现一种探针, 来抓取相应的特征到中心端 master 组件进行下一步诊断和容错决策。

百度集合通信库 BCCL 是百度智能云推出的一款面向大模型训练场景优化的集合通信库。

BCCL 基于开源的 NCCL 进行了功能扩展和能力增强, 针对大模型训练场景在可观测性、故障诊断、稳定性等方面进行优化, 进一步提升集合通信库的可运维能力。相比 NCCL,BCCL 的关键特性如下:

* 可观测性:新增集合通信带宽实时统计能力;

* 故障诊断:新增集合通信 hang 时的故障诊断能力;

* 稳定性:增强网络稳定性和故障容错能力;

* 性能优化:提升大模型训练主流 GPU 芯片的集合通信性能。

4.2.    训练 hang 的自动诊断

有了以上感知手段, 我们需要进一步的诊断、定位, 来确定是否真的发生了 hang, 以及 hang 的具体位置。具体的来讲,master 收集到各类 agent 的数据后, 会做一些综合分析:

1. 是否真的发生了 hang?感知阶段各种探针只能探测到 hang 的一种特征, 并没有办法 100% 的确定是否真的 hang 住了, 事实上不侵入用户进程是很难做到 100% 确定 hang 的。因此, 为了提高 hang 的判定准确率, 我们需要将各种特种综合起来判断, 探针上报到 master 后, 由一个 hang 诊断模块, 按照一个时间窗口 (例如 5 分钟), 进行综合判断。如果在时间窗口内日志、监控、进程调用栈、通信库中有 2 条以上都处于不处于活跃状态时, 我们判断任务真正发生了 hang。

2.hang 的具体发生的位置?确定任务 hang 了之后, 我们需要找到 hang 所在的节点来对它进行隔离。因此诊断模块需要在探针上报的数据中进一步找寻特征, 来确定 hang 发生的位置:

a. BCCL Tracehang 诊断:在感知阶段,BCCL 可以在通信库层面对所有 rank 的通信进行打点。如果有节点一直未完成通信则是发生了 hang。但是此节点可能并非真正发生 hang 的源头, 有可能是在等待其他节点完成通信。诊断模块可以根据 BCCL 打印的通信组信息, 进行交叉判断, 如果某个节点在多个通信组中都未完成通信, 那这个节点就是 hang 的源头。

b. RDMA/GPU 指标诊断:上文中我们提到, 通信阶段发生 hang 之后, 所有 rank 的 RDMA 流量都会降到 0, 而同时绝大部分 rank 的 GPU 利用率持续为 100%, 只有某一两个 rank 的 GPU 利用率为 0, 那这个 rank 很有可能是 hang 的源头。

c. 进程调用栈诊断:进程调用栈也可以作为一个 hang 源头诊断的重要参考。当发生 hang 之后, 绝大部分的 rank 都要么处于 barrier 等待状态, 要么处于通信等待阶段。只有个别的 rank 卡在其他函数上, 那么通过对比分析, 可以将调用栈与其他 rank 不同的节点初步判定为 hang 的源头。

d. 综合诊断:上面 3 种特征为我们提供了 hang 的诊断依据, 将 3 者关联起来分析后, 我们基本上可以比较准确的确定一个具体的 hang 的源头, 再结合硬件故障感知的相关信息可以进一步明确根因。

4.3. 基于 eBPF 的隐式故障感知与诊断在复杂的大规模分布式训练场景中, 传统用户态监控往往难以捕获系统内核层面的异常事件。百度百舸基于 eBPF(Extended Berkeley Packet Filter) 技术的隐式故障感知体系, 能够在不侵入用户代码的前提下, 对训练进程的系统调用、网络通信、CPU 调度等内核态行为以及训练框架关键函数运行时间建立立体观测能力。eBPF 探针部署原理通过在内核关键路径注入轻量级探针, 实现低开销的系统级行为捕获。针对训练场景特点, 主要聚焦 4 类事件跟踪:

训练关键函数跟踪:微秒级跟踪训练过程中, 前向计算、反向计算、集合通信操作等关键函数执行耗时, 记录函数间调用关系。

进程调度阻塞跟踪:挂钩 sched_switch 事件, 检测进程在 TASK_UNINTERRUPTIBLE 状态持续时间, 当单次持续超过阈值 (如 5 秒) 时捕获调用栈。

CUDA 运行时 API 监控:通过 uprobe 在 libcuda.so 等关键库注入探针, 记录 CUDA API 调用耗时分布。

RDMA Verbs 级通信监控:在 ibv_post_send/ibv_poll_cq 等核心通信接口设置观测点, 统计通信时延分布。

结合上面 4 类事件, 完成以下 2 类数据分析:

单体异常探测基线与实时数据对比。

群体一致性检测。采用卡间对比算法, 当某一 rank 的以下指标偏离集群中位数超过阈值时判定异常, 包括系统调用频率、进程就绪队列等待时长、NVLink/RDMA 带宽利用率等。

基于以上所述方法, 百度百舸针对以下 2 类典型的隐式故障进行诊断:

训练 hang 根因定位。通过关联 eBPF 捕获的多维度数据进行如下操作:

当检测到某 rank 的 GPU  Kernel 执行出现分钟级空跑 (SM 利用率 > 70% 但无有效计算输出)。

同时伴随该节点 RDMA QP 状态停滞 (ibv_poll_cq 无新完成事件)。

内核调度器显示进程处于 D 状态超过阈值。

性能抖动溯源。基于 eBPF 火焰图、时序图等进行分析:

抓取发生性能下降时段的 CPU on-cpu/off-cpu 堆栈。

对比正常时段数据, 识别出异常的锁竞争 (futex 调用占比上升)。

结合 NUMA 内存访问统计, 定位跨 NUMA 内存访问导致的 TLB 颠簸问题。

此类技术已在百度百舸的万卡规模训练集群中验证, 相比单纯依赖应用层监控的方案,将隐式故障的平均检测时间从分钟级缩短至秒级, 诊断准确率提升 40% 以上。

通过与既有硬件故障感知服务、BCCL 通信库监测体系联动, 百度百舸形成了覆盖从硬件到系统内核再到应用层的立体化诊断能力。

5.    任务故障恢复的时效性保障

故障恢复的时效性也是容错能力的一个重要指标, 反映的是任务从故障发生到再次重新进入训练迭代的时间, 恢复效率越高则算力浪费越少。影响到任务恢复效率有 2 个重要因素, 一是任务平均中断时间, 二是训练重算时间。5.1. 多级重启策略减少故障中断时间

任务发生异常后, 上文中我们提到需要经过故障自动感知、诊断和自愈等 3 个环节, 那么减少中断时间的核心思想, 就是尽可能的缩短这 3 个环节的时间, 通过多维度的感知、诊断手段可以将故障发现、定位的时效性降低至分钟级甚至秒级。自愈则需要能够根据不同的诊断结果进行分级恢复和故障屏蔽的能力:

单点显式故障:重调度异常节点 (replace), 对节点进行集群级别屏蔽。

单点隐式故障:重调度异常节点, 对节点进行任务级别屏蔽。

非单点故障:原地重启尝试恢复 (restart), 无法恢复时重新调度所有节点 (resubmit)。

通过多级重启策略, 尽可能避免单点故障引发全部节点的重新调度。在万卡级别的训练场景中,百度百舸将大部分训练异常场景恢复时间从过去的 30min 缩短至现在的 30s 内, 成功率到 95%+。

5.2.    触发式 checkpoint 减少训练重算时间

除了上述的多级任务重启策略外, 另一个提高任务故障恢复效率的重要手段就是减少训练重算时间。在探讨具体技术方案之前, 我们先来看看目前主流的 checkpoint 保存策略。

传统的 checkpoint 保存通常采用固定间隔策略, 比如每隔 N 个 step 或每隔 T 小时保存一次, 这种方式实现简单但缺乏灵活性, 可能会产生大量冗余存储, 同时在故障发生时可能会损失较多训练进度。

而触发式 checkpoint 则是一种更智能的方案, 它根据特定条件或异常事件 (如故障、显存不足、显式指令等) 动态触发模型状态保存。其核心目标是通过灵活的控制保存时机, 减少不必要的存储开销和训练中断时间, 从而降低因频繁或冗余保存导致的重算时间浪费。

随着大模型训练规模的扩大, 还有一种更激进的「零重复 checkpoint」技术, 即在每个训练 step 都保存一次 checkpoint。这种方案的优势在于可以将重算时间降到最低, 确保故障发生时能够从最近的 step 恢复, 几乎不会损失训练进度。但其显著的缺点是存储开销巨大, 即使采用增量式存储, 仍然需要相当大的存储空间和 I/O 带宽。此外, 频繁的 checkpoint 操作也可能影响训练性能。

相比之下, 触发式 checkpoint 走的是一条平衡之路。我们来看下它实现的几个核心要点:

集成容错:训练进程集成容错的故障感知与定位机制, 在进程退出前自动触发保存。这种主动感知机制能够在故障发生的第一时间保存训练状态, 最大限度减少进度损失。

高速转储:异步 checkpoint 保存机制会将 checkpoint 暂存到共享内存中, 再由外部程序转储至磁盘。当某个节点异常时, 容错组件会拉起新节点, 并在新节点训练进程启动前, 利用 RDMA 技术实现 checkpoint 快速从故障节点转储至新节点, 这大大减少了从远程存储拉取 checkpoint 的时间。

冗余备份:触发式 checkpoint 也并非完美无缺, 例如在节点发生内核 crash 等严重故障时, 可能无法触发自动保存。因此, 需要通过定期的冗余备份机制进行兜底, 确保 checkpoint 不会完全丢失。

实践表明, 当触发式 checkpoint 与异步、增量式的 checkpoint 机制结合使用时, 可以在保证数据安全性的同时, 显著提高 checkpoint 保存效率, 减少训练重算时间。

相比零重复 checkpoint 的重型方案, 触发式 checkpoint 提供了一个更实用的折中方案, 在合理的存储开销下实现较好的容错效果。当然, 具体选择哪种方案, 还需要根据实际的训练规模、硬件条件和可用资源来权衡。

随着分布式训练规模的持续增长, 相信未来会出现更多创新的 checkpoint 方案, 比如基于预测的主动保存策略、多级存储架构的智能调度等, 这些都将为提高大规模训练的可靠性提供新的可能。

6. 业务发展对稳定性的要求

AI 训练的稳定性管理已经演变为智能时代的精密工程。从最初靠人工重启解决问题的摸索阶段, 到如今能自动感知异常、快速恢复的智能系统, 每一次进步都映照着算力规模的跨越式发展。

让人不禁思考, 在未来十万卡集群的算力洪流中, 或许会出现更精妙的动态平衡方案:既能像鹰隼般敏锐捕捉故障征兆, 又能如雁群迁移般智能调度资源, 在秒级恢复与 PB 级存储成本之间找到新的平衡支点。

目前百度百舸支持厂内千卡和万卡集群有效训练时长已经可达 99.5%, 为客户大模型的预训练保驾护航, 比如国内第一个数学大模型——九章算术, 国内第一个类 Sora 大模型——Vidu 等。

来源:互联网

最新文章

极客公园

用极客视角,追踪你不可错过的科技圈.

极客之选

新鲜、有趣的硬件产品,第一时间为你呈现。

张鹏科技商业观察

聊科技,谈商业。