想象你是一家建筑公司的总指挥,接了一个大活:要在一年内建起一座 100 层的智能大厦。你调来一万名工人同时施工,他们有的砌墙、有的运料、有的搭脚手架。开工第一天,老师傅就泼来一盆冷水:一万个人里,今天一定有人头疼脑热、磕碰扭伤,甚至有人会闹脾气撂挑子。这不是运气不好,而是数学规律。可真正有经验的工程公司不会因此停工,他们会安排监工随时点名、让工人每天写施工日志、在关键楼层留下施工记录、关键时刻还有机动队顶班——这套「让工地扛得住意外」的制度,就是 GPU 集群里的故障容错。一台 GPU 卡,稳定运行很多年不出错很正常;但一万张卡同时开工,每小时都可能有人「倒下」。如果不能优雅地应对这些意外,整个大模型的训练就会反复归零,像一座永远盖不到顶层的大楼。
掌握集群故障容错,你就能在千卡级训练任务中把「意外中断」从事故变成日常流程——这是大模型时代 AI 工程师最值钱的基本功之一。
可视化演示
展示集群节点健康监测与故障检测、检查点保存与恢复机制、任务迁移与重调度流程,交互切换查看集群容错核心机制。
本节配有交互动效(进入视口后自动加载,约 3KB)。
故障检测:心跳监测与异常判定 心跳探针定期检测节点健康状态 超时未响应标记为故障触发容错流程 timeout > 3*heartbeat_interval 快速检测减少故障扩散影响
1 故障为何频繁
一万人的工地,每天都会有人不舒服,这几乎是确定的。为什么?不是因为工人们身体差,而是因为人太多了。哪怕每个人生病的概率只有万分之一,一万个人里今天至少一个人生病的概率也会接近三分之二。GPU 集群也面临同样的处境:单张 GPU 卡的故障率其实很低,但当你把一千张、一万张卡组成一个集群去训练大模型时,「某张卡出问题」就不再是「如果」,而是「今天什么时候」的问题。
在容错领域,衡量这种「常态」常用两个指标:单卡故障率 \(p\) 和平均故障间隔时间(MTBF,Mean Time Between Failures)。MTBF 表示相邻两次故障之间平均正常工作的时长。比如某型号 GPU 的 MTBF 是 100 万小时,听起来很长,但那是「一张卡」的指标。当一千张卡同时工作时,这个数字就要除以一千。
假设一张卡每小时故障率 \(p=0.001\),一万张卡组成的集群每小时期望故障数 \(E=10\)——也就是说,平均每 6 分钟就会有一张卡出问题。这还不是最坏的情况:如果训练框架没有容错机制,任何一张卡故障都会导致整个训练任务崩溃,所有进度归零。所以,成熟的容错设计第一步,就是接受一个残酷的现实:故障不是异常,而是稳态。工头从开工第一天就按「每天都会有人倒下」来安排人力,而不是祈祷大家都不生病。
- 单卡故障率 p指一张 GPU 卡在单位时间内(比如每小时)发生故障的概率,它是整个计算的起点。工程上通常通过长期统计获得。
- 显卡数量 N集群中参与同一训练任务的 GPU 总张数。N 越大,故障被「放大」得越明显。
- 期望故障数 E表示单位时间内集群平均发生的故障次数。当 \(E=1\) 时,意味着平均每小时就会遇上一次故障。
2 故障类型扫描
工地上的意外五花八门:有人扭伤了脚,这是「硬件故障」;有人被堵在路上运不来砖,这是「网络故障」;有人听错了指令砌歪了墙,这是「软件故障」。聪明的总指挥不会对所有意外都用同一种办法,他会先「分诊」,再对症下药。
GPU 集群的故障也一样,先分清类型才能设计对应的容错策略。硬件故障包括 GPU 芯片损坏、显存报错、电源老化、散热失效等,表现为节点宕机或计算错误——相当于工人直接干不了活了。网络故障包括光纤中断、网卡降速、交换机拥塞,表现为节点之间通信超时、数据丢包——相当于运料通道堵住了。软件故障则包括驱动崩溃、CUDA 报错、训练进程被杀、容器 OOM 等,表现为计算进程异常退出——相当于指令执行到一半乱套了。
工程上还用「可用率」来量化一个系统到底有多可靠。它衡量的是正常运行时间占总时间的比例:
故障的影响范围也分等级:单卡故障只需把任务迁移到同节点的另一张卡;单节点故障需要整机下线检修;机架级故障(比如电源模块损坏)会影响几十张卡;而全集群故障(机房断电、核心交换机宕机)则需要降级运行甚至停机抢修。就像工地上有人扭脚可以现场处理,工人重伤才送医院,整层楼着火就要启动全工地应急预案。分诊清楚,是为了不浪费治疗资源,也为了不错过真正要命的伤情。
- 正常运行时间 \(T_{\text{up}}\)系统没有任何故障、能持续提供服务的时间总和,是可用率的分子。
- 故障停机时间 \(T_{\text{down}}\)从故障发生到系统完全恢复之间损失的时间,包括故障发现时间、重启时间和数据恢复时间。
- 可用率 A把两个时间代入公式,得到一个 0 到 1 之间的比例。99.9% 可用率意味着一年约 8.7 小时停机。
3 哨兵值班检测
工地上有一条铁规矩:监工每小时拿着点名册巡检一次,谁没应声就要立刻跑过去看看。这种「点名」就是最朴素的心跳检测。GPU 集群里的管理节点,也像一个拿着点名册的监工,周期性地问每一台机器:你还活着吗?还干得动吗?
在分布式训练中,每个节点会周期性地向调度器发送一个「心跳信号」——一条极小的网络消息,相当于工人喊一声「到」。如果调度器在设定时间内没有收到某节点的心跳,就会把该节点标记为「疑似失联」。为了确认节点是「真死」还是「假死」,系统还会通过带外管理通道(如 IPMI)直接检查机器的电源状态,或者发起健康探测,比如 ping 一下网络、查一下 GPU 的温度和显存占用。日志系统也会把所有节点的错误信息汇聚起来,帮助定位故障根因。
这里的关键是「多久没收到心跳才算故障」。设得太短,一次网络抖动就会误报;设得太长,坏节点会拖着整个训练任务迟迟不被发现。工程上通常这样计算超时阈值:
监工巡检的意义在于「早发现、早处理」。没有监工的工地,工人晕在角落可能半天都没人发现;没有心跳检测的集群,一张卡静默失效后,其他节点还会傻等它的梯度,整个训练任务卡死几十分钟才发现异常。监控系统就是容错的第一道防线——它像一双永远睁着的眼睛,把故障从「未知」变成「已知」,后续的恢复手段才有了用武之地。
- 心跳间隔 \(T_{\text{interval}}\)节点每隔多久发一次心跳。间隔越短,故障发现越快,但心跳消息本身也占用网络带宽。
- 网络抖动余量 \(T_{\text{jitter}}\)网络传输延迟是波动的,允许一定的「迟到」时间,避免把正常的网络慢速误判为节点故障。
- 超时阈值 \(T_{\text{out}}\)调度器从上次收到心跳开始计时,超过这个时间没等到下一次心跳,就触发告警并进入故障确认流程。
4 检查点策略
有经验的老师傅有一个习惯:每砌完一层楼,就在施工日志上记清楚这层的墙面尺寸、钢筋数量和材料批次。万一后面发现哪儿砌错了,最多拆掉一层重新来,绝不会推倒整栋楼。这份「施工日志」,对应到 GPU 集群训练里就是 Checkpoint(检查点)。
分布式训练是一个漫长的连续过程,模型权重在成千上万次迭代中一点点更新。如果中途故障导致进程退出,内存里的参数会全部丢失。所以训练框架会周期性地把「当前进度」保存到磁盘上:包括模型权重、优化器状态(如动量、学习率调度)、当前迭代步数等。故障发生时,训练任务不是从零开始,而是从最近一次 Checkpoint 恢复。这就是检查点容错的基本思想。
那么,检查点应该多久保存一次?保存太频繁,写磁盘的开销会拖慢训练;保存太少,故障后回退的损失会很大。假设故障发生 \(F\) 次、检查点间隔为 \(\tau\),平均每次故障只会回退大约半个周期:
为了进一步降低保存开销,业界还发展出了异步保存技术:训练不暂停,而是把当前模型参数复制到内存缓冲区,由后台线程慢慢写入磁盘——相当于施工队继续干活,让文员在边上偷偷复印施工日志。如今 HuggingFace Transformers、PyTorch Lightning、DeepSpeed 等框架都内置了 Checkpoint 接口,大模型训练的标配做法是「每训练 N 步保存一次 + 训练结束前强制保存」。施工日志记得越勤,重来的代价越小;但日志本身也不能记到影响干活,聪明的施工队总是在「损失」和「成本」之间找到平衡点。
- 故障次数 F训练全过程中发生故障的总次数。故障越频繁,检查点策略越重要。
- 检查点间隔 \(\tau\)每训练多久保存一次检查点。假设故障是随机发生的,故障点平均落在两个检查点中间,因此平均回退半个间隔。
- 总回退损失 \(T_{\text{loss}}\)把所有故障的平均回退量累加起来,得到训练总时间中「白干」的部分。
5 重调度与弹性
工地上最怕的不是有人倒下,而是倒下之后没人接替他的工作。好的工头手里总是留几个「机动工」,谁出问题马上换人顶班,必要时还能临时调来一批援兵。GPU 集群里的调度器,就是那个永远在调配人力的工头。
当故障被检测确认后,调度器会做两件事:第一,把故障节点上正在运行的任务杀掉并重新排队;第二,为这些任务寻找新的健康节点,让训练从最近的检查点恢复。这个过程叫做重调度。如果集群有预留的备用节点(对应先招好的机动工),调度器能立刻分配新节点;如果没有预留,就得等队列里其他任务结束腾出资源,恢复时间会显著拉长。
恢复到底要多久?可以拆成三个部分:发现故障要多久、重新分配资源要多久、把检查点从磁盘加载回显存要多久:
更进一步的弹性伸缩能力,让集群可以在训练高峰期临时扩容、低谷期自动缩容,故障时还能自动补足节点配额。调度器还会根据任务优先级决定谁来抢占资源:重要的训练任务可以挤掉低优先级的推理任务,快速恢复生产——工地上就相当于「救火优先于装修」。机动工的数量、援兵的速度,决定了工程恢复快慢。调度器容错的核心思想是:不要祈祷不会出事,而是确保出事之后,好人手能立刻补上。
- 故障检测时间 \(T_{\text{detect}}\)从故障实际发生到调度器确认节点失效的耗时,心跳间隔越短,这个时间越小。
- 资源调度时间 \(T_{\text{schedule}}\)调度器为新任务分配节点、拉起容器、初始化环境的时间。若集群有预留资源,这个时间接近常数;否则需要排队等待。
- 检查点加载时间 \(T_{\text{load}}\)从分布式存储中读取检查点文件、把模型权重加载进显存的开销。模型越大、存储越慢,这一项越长。
6 通信梯度容错
一万人同时在一栋楼上砌墙,如果各干各的,这栋楼必然歪七扭八。所以每砌一段,大家必须对齐一下施工方案。可问题是,让一万人两两互相对方案,会活活堵死所有通道。GPU 集群训练大模型同样面临这个难题:每个 GPU 算完一批数据后,要把自己的「梯度」告诉所有人,大家取平均后再继续下一步。这个「对齐施工方案」的操作,在分布式训练里叫 AllReduce。
早期的参数服务器方案,相当于让所有人把方案都交到总工头手里,总工头汇总后再挨个发回去。这个设计有个致命弱点:总工头撑不住一万人的消息量,而且总工头一倒,整个工地立刻瘫痪。为了解决这个单点问题,业界发明了 Ring-AllReduce——让所有 GPU 排成一个环,每个人只把计算结果传给「下一个人」,像接力传话一样,绕一圈之后所有人就都拿到了完整结果。没有中心节点,也就不存在单点瓶颈。
Ring-AllReduce 最迷人的地方在于它的通信量:假设每个节点要同步的总数据量为 \(S\),节点数为 \(N\),那么每个节点实际传输的数据量大约是:
为了让通信更皮实,工程上还有配套手段:分桶通信把大梯度切成小桶并行发送,某个桶失败只需重传该桶;梯度压缩(量化、稀疏化)先把消息「压缩」再传,减少带宽压力。通信层的容错还要处理连接断开后的自动重连与消息重试。回看工地:接力传话比总工头广播更抗揍——没有一个人需要扛下所有消息,多来几百个工人也不会把通道堵死。这就是大规模施工队的基本功。
- 总数据量 S每个节点需要同步的梯度总大小。模型越大、批次越大,S 越大。
- 分片因子 (N-1)/NRing-AllReduce 把总数据分成 N 份,每个节点每轮只处理自己那份的 1/N,第一轮先传一部分,后续轮次接力汇总。
- 环上转两圈整个算法分为「分散 reduce」和「广播」两个阶段,每个阶段要绕环 N-1 次,所以每个节点总通信量为 \(2(N-1)\) 份小片数据,即 \(2(N-1) \times S / N\)。
7 冗余双保险
工地上最怕的不是缺人,而是图纸被水泡了、被火烧了——那是全队的「大脑」。有经验的工程公司有两手准备:图纸复印多份分处存放,同时多招一支预备队。GPU 集群的容错也有这「双保险」:数据冗余和算力冗余。
数据冗余针对的是训练数据和检查点的安全。同一份数据在多个节点上存多份副本,某一份损坏了,其他副本照样能读。为了节省存储空间,还可以用纠删码(Erasure Coding):把 4 块数据经数学编码变成 6 块存起来,任意坏掉 2 块,都能用剩下的 4 块把原始数据还原——相当于把图纸拆成碎片分散保管,丢几片也能拼回来。副本数与可用性的关系可以用公式刻画:
算力冗余则是对应「预备队」:N+1 方案就是额外准备一台空闲节点,任何一台工作节点故障,备用节点立刻顶上;主备切换则让关键服务(比如参数服务器、调度器主节点)运行在「一主一备」的模式下,主节点故障时备节点自动接管,不让整个集群失去「大脑」。多印一份图纸的成本,永远比丢了图纸重新画要低。数据冗余保住了「记忆」,算力冗余保住了「人手」,两样都保住了,训练任务才能在各种意外中活下来。
- 单副本故障率 \((1-p)\)某一份数据丢失或不可读的概率。若单副本可用性为 90%,则不可用概率为 10%。
- R 个副本同时损坏当 R 份副本分别存放在不同节点上时(假设故障独立),所有副本都不可用的概率是 \((1-p)^R\)。
- 整体可用性 P用 1 减去「全部失效」的概率,就是「至少一个副本可用」的概率。
8 工程实践
再好的应急预案,不演练也是废纸。成熟的工程公司每季度搞一次消防演习:拉响警报、疏散人群、清点人数。真正出事那天,大家靠肌肉记忆就能行动,不会乱成一锅粥。工业界的集群容错,也是一套需要反复演练的工程制度。
这套制度从下到上分为几个层次。框架层:PyTorch 的 torchrun 支持节点故障后自动重启训练;DeepSpeed、Megatron 提供一键 Checkpoint 接口;Horovod 内置了弹性训练(Elastic Training),允许训练过程中动态增减节点。平台层:Kubernetes 能自动重新拉起失败的任务 Pod,配合完整的健康检查与重启策略;云厂商如 AWS SageMaker、阿里云 PAI 则把「训练容错」做成了开箱即用的托管能力——用户只需指定检查点频率和最大重试次数,平台负责其余一切。全链路设计则强调每个环节都要有兜底:监控发现问题 → 告警触发 → 自动保存检查点 → 重启任务 → 加载最近检查点 → 继续训练,这条链路任何一环断了,容错都会失效。
验证这套链路是否真正可靠,靠的是混沌故障演练(Chaos Engineering)。工程师主动注入故障:随机杀掉一个训练进程、拔掉一根网线、关掉一台机器,然后观察系统能否在规定时间内自动恢复。故障覆盖率可以量化演练的充分程度:
演练不是折腾,而是把「容错」从纸面方案变成肌肉记忆。真正跑过千卡训练的公司都知道:训练顺利是侥幸,遇到故障才是日常。能把每一次故障都变成一次安静的重启、一次无损的恢复,这才是集群故障容错真正要交付的能力——让 AI 工程师可以放心地把几百万的算力账单,交给一群「随时会有人倒下但工程永远不倒」的 GPU 集群。
- 已演练故障类型数 \(f_{\text{tested}}\)通过故障注入工具(如 Chaos Mesh、网卡中断脚本)实际模拟过的故障种类,如进程崩溃、节点宕机、网络分区等。
- 总故障类型数 \(f_{\text{total}}\)根据故障模型枚举出的所有可能故障场景,包括单卡、单节点、机架、网络、软件五类。
- 覆盖率 C比值越接近 1,说明容错体系被验证得越充分。实际操作中还会用两个关键指标验收:RTO(恢复时间目标)和 RPO(恢复点目标)。
AI 应用场景
大模型预训练:千卡集群的马拉松
阶段:模型训练与运维
解决的问题:一个千亿参数大模型预训练动辄运行数周甚至数月,训练中途 GPU 故障几乎必然发生。没有容错机制时,任何一张卡故障都可能导致整个训练任务崩溃、进度归零,造成数百万算力成本的浪费。容错机制让故障后的损失从「从头再来」缩减到「回退半小时」。
具体案例:某公司训练 1750 亿参数的大语言模型,使用 2048 张 A100 GPU,为期 60 天。训练期间记录到 300 余次节点级故障,靠每 15 分钟一次的 Checkpoint + 调度器自动重启 + 备用节点自动补位,训练得以连续推进,最终顺利完成——平均每 5 小时就发生一次故障,但训练从未中断超过 10 分钟。
云上训练平台:把容错封装成产品
阶段:平台建设与资源调度
解决的问题:中小团队既没有专业运维,也没有万卡集群经验,但同样需要可靠的训练能力。云厂商把容错能力封装成平台服务:用户提交训练任务时只需指定检查点路径和最大重试次数,平台自动处理节点故障检测、任务重启和资源调度,让「容错」变成用户无感知的默认能力。
具体案例:阿里云 PAI 的分布式训练平台支持容错自动恢复,用户提交 PyTorch 训练任务后,平台自动监控每个节点的心跳。某智能驾驶公司用该平台训练感知模型,高峰期同时运行 200 个训练任务,平台每月自动恢复故障任务超 800 次,人工介入几乎为零。
自动驾驶数据工厂:弹性容错的长尾训练
阶段:数据迭代与模型增量训练
解决的问题:自动驾驶模型需要不断用新采集的路测数据做增量训练,训练任务频繁、周期短、波动大。弹性容错让集群在白天推理任务多时自动缩容,夜间训练高峰自动扩容;节点故障时调度器自动迁移任务到空闲节点,保证每一个训练任务都能按时完成。
具体案例:某自动驾驶公司每天新增 5000 万帧道路数据,模型训练团队使用 Kubernetes + 自研调度器管理 500 张 GPU。每周约发生 20 次 GPU 故障,全部由「检测 → 迁移 → 检查点恢复」流程自动处理,训练任务完成率稳定在 99% 以上。
Python 演示
import random class FaultTolerantCluster: """模拟一个带检查点与故障回退的GPU集群训练过程""" def __init__(self, total_work=100, ckpt_interval=10, fault_rate=0.03, has_ckpt=True): self.total_work = total_work self.ckpt_interval = ckpt_interval self.fault_rate = fault_rate self.has_ckpt = has_ckpt self.progress = 0 # 当前训练进度 self.last_ckpt = 0 # 最近一次检查点保存的进度 self.time = 0 # 训练耗时(时间步) self.fault_count = 0 # 故障次数 self.ckpt_count = 0 # 检查点保存次数 def step_run(self): """前进一个时间步:先判断是否故障,再决定是否前进""" if random.random() < self.fault_rate: self.fault_count += 1 if self.has_ckpt: self.progress = self.last_ckpt else: self.progress = 0 else: self.progress += 1 self.time += 1 if self.has_ckpt and self.progress - self.last_ckpt >= self.ckpt_interval: self.last_ckpt = self.progress self.ckpt_count += 1 def train(self): """运行训练直到进度达到总工作量,返回耗时""" while self.progress < self.total_work: self.step_run() return self.time def report(self): print("故障次数:", self.fault_count) print("检查点保存次数:", self.ckpt_count) print("耗时:", self.time) def simulate(has_ckpt=True, total_work=100, ckpt_interval=10, fault_rate=0.03): cluster = FaultTolerantCluster(total_work, ckpt_interval, fault_rate, has_ckpt) cost = cluster.train() return cost, cluster if __name__ == "__main__": random.seed(42) for has_ckpt in (False, True): cost, cluster = simulate(has_ckpt=has_ckpt) label = "有检查点" if has_ckpt else "无检查点" print("--- " + label + " ---") cluster.report() print("训练完成总耗时:", cost)
if random.random() < self.fault_rate:每个时间步掷一次骰子,决定本步是否发生故障,对应集群中「故障是概率事件」的本质。self.progress = self.last_ckpt有检查点时,故障只回退到最近保存点,而不是归零。self.progress = 0无检查点时,故障会让所有进度清零,只能从头训练。if self.has_ckpt and self.progress - self.last_ckpt >= self.ckpt_interval:判断是否该保存新检查点:当进度超过上次保存点一个完整间隔时,记录新检查点。self.ckpt_count += 1每次保存检查点都计数,反映「保存频率 × 训练时长」的存储开销。while self.progress < self.total_work:训练主循环,只要没达到总工作量就继续,对应真实训练中「迭代到收敛为止」。
常见误区
误区经常听到有人说:「我那张 GPU 用了三年都没坏,集群应该很稳定吧?故障是低概率事件,没必要天天提心吊胆,出了问题再重启一次不就行了。」这种想法在单机场景下没问题,但放到集群里就完全错了。
正解单卡故障率低 ≠ 集群故障率低。就像一个人一年感冒一次很正常,但一万人里每天都有几十人感冒。假设单卡每小时故障率 0.001,一万张卡的集群每小时期望故障数就是 10——平均每 6 分钟一次。容错设计的首要原则就是「先接受故障是常态,再谈如何应对」。
为何常见:人天生用「自身经验」推断「系统行为」。单卡长期稳定运行的经历,让人低估了「规模化」对故障概率的放大效应。
误区「反正检查点能减少损失,那每秒保存一次不就好了?这样故障最多损失一秒的进度。」不少人把检查点当成免费的后悔药,总觉得保存越勤越保险。
正解检查点本身有代价:写磁盘占用存储带宽、同步所有节点状态可能阻塞训练、加载时还要读回内存。检查点间隔从 1 小时缩短到 1 分钟,回退损失减少了 98%,但保存开销可能上涨 60 倍。工程实践中通常按「回退损失 ≈ 保存开销」的原则寻找平衡点,还会用异步保存来稀释成本。
为何常见:只看到了检查点「减少损失」的一面,忽略了「保存本身也消耗资源」的另一面。任何工程决策都是权衡,不是越极端越好。
误区「GPU 坏了?让运维换一张新卡,把任务重新提交一次不就好了?」这种想法把容错想得太简单——换卡不是换零件,训练进度也不是重新提交就能恢复的。
正解分布式训练的进度分布在一千张卡的显存里,任何一张卡的显存内容丢失,整个训练状态的全局一致性就被破坏了。即使换上新卡,其他 999 张卡的参数也和故障瞬间不一致,必须配合 Checkpoint、梯度同步和重调度机制才能继续。只换卡而不管数据一致性,训练就会在算错的基础上继续跑,产出没有意义的模型。
为何常见:把 GPU 集群类比成普通服务器集群,以为硬件替换 + 任务重启就能恢复。实际上分布式训练有「全局状态」的约束,容错必须从「数据 + 计算 + 通信」三个维度同时设计。
误区「PyTorch 不是支持 torchrun 自动重启吗?那我只要把训练任务交给框架,就不用管容错了。」很多初学者以为框架的容错能力是万能的保底。
正解框架只能保证「进程重启」这一件事做得足够好,但它依赖很多外部条件:检查点要存在共享存储上(否则重启后读不到)、故障节点的任务要能被调度器重新分配、网络环境要允许重连、数据加载要支持断点续读。任何一个环节配置错误,框架的「自动重启」都会变成无限重启。真正的容错是全链路设计:监控、存储、调度、框架各司其职,缺一不可。
为何常见:把复杂的系统工程简化为「某个工具的能力」。理解容错需要系统思维,而不是找到某个银弹。
面试题
Q1. 关于万卡集群的故障,以下说法正确的是?
- A.单卡几乎不会故障,集群因此非常稳定
- B.单卡故障率不高,集群规模大后故障成常态← 正确答案
- C.只需关注单卡稳定性,无需考虑整体规模
- D.集群故障只会发生在刚上线的第一天
答案:B。单卡故障率低,但集群的期望故障数等于 N×p,规模越大故障越频繁。就像一万人工地每天都有人生病,不能因为「单个人很少生病」就认为「一万人不会有人生病」。A 忽略了规模化效应,C 和 D 则完全违背集群故障的统计规律。
Q2. 平均故障间隔时间 MTBF 的正确含义是?
- A.一次故障发生后恢复所需的平均时长
- B.相邻两次故障之间稳定工作的平均时长← 正确答案
- C.训练任务提交到完成所需的平均总时长
- D.单张 GPU 从全新出厂到报废的平均寿命
答案:B。MTBF(Mean Time Between Failures)描述的是「两次相邻故障之间」的平均正常工作时间,是可靠性的核心指标。A 描述的是平均恢复时间(MTTR),C 描述的是任务耗时,D 描述的是寿命而非故障间隔。MTBF 反映的是「多久坏一次」,而不是「坏了多久恢复」。
Q3. 心跳超时阈值通常需要考虑什么?
- A.模型参数量和训练数据的规模大小
- B.心跳间隔时间加上网络抖动的时间余量← 正确答案
- C.GPU 显存容量和功耗上限指标
- D.检查点保存频率和存储空间大小
答案:B。心跳超时阈值 = 心跳间隔 + 网络抖动余量。设置太短会把正常网络延迟误判为节点故障,设置太长则故障发现太慢。A、C、D 分别属于模型、硬件和存储维度的问题,与心跳超时判定的直接逻辑无关。
Q4. 检查点保存频率过高,主要代价是?
- A.模型训练出来的精度会显著下降
- B.存储开销和保存暂停的时间上升← 正确答案
- C.集群中节点故障发生频率提高
- D.训练数据在磁盘上自动损毁
答案:B。检查点保存需要写磁盘、同步状态,频率过高会占用存储带宽并暂停训练,导致有效训练时间被压缩。它不影响模型精度(A 错),不改变硬件故障率(C 错),也不会损坏数据(D 错)。
Q5. Ring-AllReduce 相比参数服务器的优势包括?
- A.避免中心节点成为性能瓶颈← 正确答案
- B.每节点通信量不随规模暴涨← 正确答案
- C.完全不需要保存检查点文件
- D.将总通信量均分到各个环节← 正确答案
答案:ABD。Ring-AllReduce 没有中心节点,所有节点构成环形接力,通信量被均分,每节点通信量约为 2S 且与节点数基本无关。参数服务器的中心节点会随规模增大成为瓶颈。它改变的是通信架构,与是否保存检查点无关,C 错。
Q6. 每卡每小时故障率 0.001,1000 卡集群平均每小时故障次数是?
- A.0.001 次,几乎不发生故障
- B.1 次,平均每小时发生一次← 正确答案
- C.1000 次,整个集群根本无法使用
- D.不确定,与集群规模没有关系
答案:B。期望故障数 E = N×p = 1000 × 0.001 = 1 次/小时。这说明即使单卡故障率低到千分之一,千卡集群也平均每小时坏一张卡。A 错在只看单卡,C 错在把故障率直接当故障次数,D 错在忽略集群规模是期望公式的核心变量。
Q7. 故障检测与确认的常用手段有哪些?
- A.周期性心跳上报确认节点存活← 正确答案
- B.带外管理通道检查电源与硬件状态← 正确答案
- C.健康探测匹配日志中的异常规则← 正确答案
- D.断电重启集群中全部机器设备
答案:ABC。心跳机制发现失联,带外管理(如 IPMI)确认硬件是否真死,日志分析定位异常根因,三者构成了「发现 → 确认 → 定位」的完整链路。D 是故障处理手段而非检测手段,而且重启全部机器属于极端操作,不是检测方案。
Q8. 检测到节点故障后,调度器首先应该做什么?
- A.将任务重新调度到健康节点上← 正确答案
- B.立即删除所有历史检查点数据
- C.把故障节点续约租给其他用户
- D.调低学习率继续在原节点上训练
答案:A。故障节点已无法承载计算任务,调度器的核心职责是把任务迁移到健康节点继续运行。B 删除检查点会让恢复失去依据,C 把故障节点租给用户没有意义,D 因为原节点已失效根本不可能继续训练。
Q9. 以下哪些属于容错设计的关键策略?
- A.周期性保存检查点便于故障后恢复← 正确答案
- B.数据多副本存储防止单点数据丢失← 正确答案
- C.故障后自动迁移任务到备用节点← 正确答案
- D.忽略偶发故障等待网络自行恢复
答案:ABC。检查点、数据冗余、任务迁移分别对应「进度恢复」「数据安全」「算力补位」,是容错的三大支柱。D 属于放任不管,偶发故障可能演变成数据损坏或任务长期卡死,不是工程上可接受的策略。
Q10. 副本数为 3、单副本可用性 90% 时,系统整体可用性约为?
- A.90.0%,增加副本数没有影响
- B.99.9%,一坏两好仍能正常读取← 正确答案
- C.30.0%,三个副本可用性取平均值
- D.99.0%,勉强达到基本可用水平
答案:B。整体可用性 P = 1 − (1−p)³ = 1 − 0.001 = 0.999,即 99.9%。三个副本独立故障时,只有三个全坏数据才不可用。A 忽略副本冗余的增益,C 混淆了概率的乘法关系,D 计算错误(0.99 对应的是两个 90% 副本的情况)。