AI硬件可靠性:从失效机理到架构加固与系统兜底
2021年前后,我参与过一个训练集群的稳定性专项。最初目标很朴素:把每周的作业中断次数压下来。真正翻日志才发现,问题根本不能笼统概括成"机器坏了"——有的是直接报错退出,有的是默默算错却一路不报警,还有的连跑十几个小时才在某个特定 kernel 上崩掉。那段时间我们把面向人工智能(AI)的硬件可靠性这个词翻来覆去地拆,才意识到它和传统服务器的可靠性完全不是一个量级的问题:负载是 7×24 满载、内存带宽长期饱和、片上 SRAM 动辄上百兆比特、工艺节点又压到 7nm 以下,任何一点微小的物理扰动都会被放大成几天甚至几周的算力浪费。这篇就按我当时的拆解路径来写:先讲清楚 AI 硬件为什么"更容易坏、坏了更贵",再讲失效机理、架构级加固、系统级兜底、验证评估,最后给一份能直接抄的排查清单。适合做 AI 芯片架构、训练平台运维、系统软件和可靠性工程的同行参考,刚入行的同学也能看懂大框架。
1. 先弄清 AI 硬件可靠性到底在解决什么问题
很多人第一次接触这个话题,会下意识把它等同于"服务器别宕机"。这个理解放在传统业务上没错,放在 AI 上就偏了。传统业务的可靠性目标是可用性——服务不中断,请求有响应,偶尔算错一个字段大不了重试一次。AI 训练的目标是计算结果的正确性与任务的完成效率,一次静默的数值错误可能让一个跑了三周的作业白费,而一次明确的宕机反倒是最"友好"的故障,因为它至少能被感知。
1.1 可靠性设计的目标是期望损失最小化,不是失效率最小化
这是我在项目里被反复纠正的一个认知。工程上我们习惯盯 FIT 数字,觉得把失效率压到某个阈值就完事了。但 AI 场景下真正该算的是一笔经济账:单次故障的代价乘以故障频次,再加上为降低故障付出的面积、功耗、性能开销,三者取得平衡才是合理设计。
举个具体的对比。一颗 AI 加速卡上有 100 Mbit 的片上 SRAM,假设没做任何保护,按地面中子环境的典型软错误率 10⁻³ FIT/Mbit 估算,整块 SRAM 的失效率大概是 0.1 FIT。折算成 MTBF 是 10¹⁰ 小时,看起来几乎永远不会坏。可是故障一旦落在 softmax 的分母、LayerNorm 的统计量或者优化器的动量缓存上,后果不是"少算一个结果",而是整个训练发散、需要回滚到几天前的检查点。把单次代价按几万卡时算进去,这个"几乎不会坏"的概率就完全不划算了。反过来,如果给这 100 Mbit 全部上三模冗余,面积翻三倍、功耗翻三倍、时序还过不去,同样不划算。所以真实的设计永远是在选择性加固:把最关键的 5% 状态位保护到极致,剩下的靠上层兜底。
提示:做可靠性预算时,务必把"错误被发现的时间延迟"作为独立变量计入。一个 1 小时后被发现的错误,和一个 3 周后才被发现的错误,损失差好几个数量级,但它们在最底层的 FIT 数字上完全一样。
1.2 AI 负载把硬件推到了传统可靠性模型的边界之外
传统数据中心服务器的可靠性模型,建立在"短时突发计算 + 大量空闲"的负载画像上。CPU 大部分时间利用率在 20% 以下,温度在阈值附近来回波动,老化进程相对温和。AI 训练完全是另一回事:加速卡连续几个月跑在 90% 以上的利用率和接近 TDP 的功耗上,结温长期贴着温度墙,供电电流持续拉满。
这种负载画像带来三个连锁反应。第一是老化加速,高温高压长期共存会显著加快偏置温度不稳定性和热载流子注入的进程,器件参数漂移在两年内就能积累到肉眼可见的程度。第二是热循环疲劳,虽然稳态温度高,但作业切换、负载波动仍然会造成结温在几十度范围内反复变化,焊点和封装材料在这种循环下会逐步产生微裂纹。第三是暴露窗口变长,瞬态故障本质上是概率事件,单位时间的翻转概率固定,跑得越久累计被打中的概率越高。一台跑 8 小时的机器和一个跑 8 周的作业,面对的风险完全不是一个量级。
1.3 2021 年这个时间点的特殊性
把时间锚定在 2021 年前后是有原因的。那两年模型参数从亿级跳到千亿级,单次训练从几天变成几周甚至几个月,单集群从几百卡扩到几千卡。这几个数字一乘,故障就从"实验室里的奇观"变成了"运维的日常"。
我算过一笔很直观的账:假设单卡的统计失效率是 5000 FIT(这个量级在加速卡上不算离谱,整机加板卡加内存加电源一起统计),那么 1000 张卡的集群总失效率是 5×10⁶ FIT,换算下来平均每 200 小时就会出一次故障,也就是八天多一次。如果集群规模扩到一万卡,MTBF 直接掉到 20 小时,一天至少一次。这个频率下,"坏了就重启"的做法彻底失效,必须从架构层面设计容错和快速恢复。这大概就是那几年行业把 RAS(可靠性、可用性、可服务性)从整机层面下沉到加速器内部设计的直接动因。
1.4 四条主线,别混着谈
我把整个问题拆成四条互不相同的主线,后面所有章节都围绕它们展开。瞬态故障来自外部辐射和封装材料的微量放射性元素,特点是随机、可恢复、不损伤器件。永久故障与老化来自器件物理退化,特点是随时间累积、不可逆。静默数据损坏不是一种独立失效机理,而是前两者的一种"结果状态"——错误发生了但没人发现。环境与供电相关故障则是温度、电压、电流瞬变引起的时序违例和功能异常。这四类的检测手段和缓解手段完全不同,混在一起谈必然抓瞎。
| 失效类别 | 典型诱因 | 时间特征 | 是否可恢复 | 主要检测手段 |
|---|---|---|---|---|
| 瞬态故障 | 中子、α 粒子、电源噪声 | 随机、瞬时 | 是(重算/纠正) | 奇偶校验、ECC、CRC |
| 老化失效 | 偏置温度不稳定、热载流子、电迁移 | 缓慢累积、不可逆 | 否(只能降级) | 老化传感器、频率裕量监测 |
| 静默数据损坏 | 上述两者未被检测的部分 | 潜伏期长 | 视场景 | 端到端校验、结果比对 |
| 供电与热异常 | 负载瞬变、散热劣化 | 突发或渐变 | 多数可恢复 | 电压监测、温度传感器 |
2. 失效机理拆解:AI 芯片到底会怎么坏
做架构设计最怕的就是"知道要加固,但不知道在加固什么"。这一节把物理层面的机理摊开讲,因为只有理解了错误是从哪来的、以什么形态出现,才能判断在哪个抽象层拦截成本最低。
2.1 瞬态故障:单粒子翻转在 AI 负载下的放大效应
高能中子或封装材料中的 α 粒子穿过硅片时,会沿轨迹电离出一串电子空穴对。如果这个电荷量超过存储单元的临界电荷,存储的位就会翻转,这就是单粒子翻转。存储单元越小、供电电压越低,临界电荷越小,翻转越容易发生。所以工艺越先进,这个问题的绝对数量反而可能上升,虽然单比特的截面在缩小,但单位面积集成的比特数涨得更快。
AI 芯片对这个特别敏感,原因在于它的存储密度。一颗训练卡上,寄存器堆、共享内存、各级缓存加起来可能有好几百兆比特的片上存储,其中相当一部分没有完整的 ECC 保护。权重、激活值、梯度、优化器状态都在这些空间里来回倒腾。
更麻烦的是放大效应。推理场景下,一个权重位翻转可能只影响一个输出 token,用户根本察觉不到。训练场景完全不同,一个被翻转的梯度会通过反向传播影响参数更新,进而污染后续所有 step 的优化轨迹;一个在 LayerNorm 统计量上的翻转会让整层输出偏移,然后被后续几十层的矩阵乘不断放大。我见过一次典型的案例:某次作业在第 3000 步附近 loss 突然抬高一个台阶然后再也不降,事后定位就是某一层的归一化统计量在某张卡上出现了偏差。
这里必须引入一个概念:架构脆弱因子。它的含义是,在所有可能被翻转的位中,真正会影响程序最终正确结果的比例。显然不是所有位都同等重要——被 mask 掉的 token、padding 区域、已经超出裁剪范围的梯度,翻了也不影响结果。所以实际的软错误率是原始翻转率乘以架构脆弱因子。做架构评估时如果只看原始翻转率,会严重高估风险,导致过度加固;只看最终结果又容易漏掉关键路径。我的经验是,先做一轮架构脆弱因子分析,把"翻转后确实会改变最终 loss"的位筛出来,再做针对性加固,性价比最高。
还要注意多比特翻转。先进工艺下,一次粒子入射可能同时影响物理上相邻的几个单元,而这些单元在逻辑地址上可能恰好属于同一个纠错字。所以光有单比特纠错不够,存储阵列必须做交织——把逻辑上相邻的位在物理上分开放,保证一次扰动最多打到每个纠错字的一位。交织的粒度要考虑工艺的电荷扩散半径,这个参数必须找工艺厂要,不能凭感觉定。
2.2 老化失效:慢变量才是真正的隐形杀手
老化是器件特性随时间退化的一类现象的统称,主要机理有四种。偏置温度不稳定性指晶体管在栅极偏压和温度共同作用下阈值电压发生漂移,表现为电路变慢,高温加剧明显。热载流子注入是沟道中的高能载流子撞击栅氧界面产生缺陷,同样导致阈值漂移和跨导下降,它跟开关频率强相关。电迁移是金属互连中的大电流密度导致原子迁移,长期下来形成空洞或小丘,最终断路或短路,跟电流密度的平方强相关。经时介质击穿是栅氧在电场长期作用下形成导电通路,一旦发生就是硬失效。
这四种机理有一个共同点:都对温度和电压极其敏感。经验上,结温每升高 10 到 15 摄氏度,多数老化机理的退化速率接近翻倍;供电电压每上浮 10%,介质击穿和电迁移的寿命会显著缩短。AI 加速卡恰好长期处在这两个加速因子上,所以它的"有效寿命"要按加速模型折算,不能简单套用消费电子的经验。
架构上应对老化的核心思路不是"阻止退化",而是感知退化并保留裕量。常见做法是在关键路径旁边放老化传感电路,定期测量延时链的翻转速度,反推当前的时序裕量;再配合片上频率电压调节,在退化后适度提高电压或降低频率维持功能。这套机制的价值在于把"某天突然全片区报错"变成"缓慢降频但持续可用",对长时间训练任务来说,后者远比前者友好。
2.3 静默数据损坏:最贵的那种"没报错"
静默数据损坏的可怕之处在于,它绕过了所有检测机制,直接以"正确数据"的身份参与计算。按检测结果可以把错误分成三类:能纠正的、能检测但纠正不了的、完全检测不到的。第三类占比不高,但造成的损失往往最大。
我踩过一次典型的坑。某个多卡作业在跑到第二天时,其中一张卡的 loss 曲线开始比其他卡缓慢偏高,但没有任何错误日志。排查了两天才发现,那片区域的 HBM 有一条链路的校验被关掉了(某次固件升级后配置被重置),一个比特的错误被反复读出但从未上报,最终污染了那一路的数据并行分支。这类问题的定位成本极高,因为它既不像宕机那样有明确时间点,也不像数值溢出那样有确定性复现路径。
从架构角度,压制静默数据损坏只能靠端到端校验。数据在从内存读出、经过计算单元、写回内存的整条链路上,至少要有一次端到端的完整性校验,任何中间环节的局部保护都不能替代它。原因很简单:局部保护只能保证"这一段传输没错",而错误可能在保护范围之外产生,或者在校验后被重新引入。这条原则在互连设计里尤其重要,后面还会展开。
2.4 把故障率算成钱:FIT、MTBF 与可用性
不用数字说话的可靠性讨论都是耍流氓。基础单位是 FIT,含义是每十亿器件小时发生一次失效。用它换算 MTBF 非常直接:MTBF 小时数等于十亿除以 FIT 值。前面提过,单卡 5000 FIT 对应 20 万小时,约 22.8 年,听起来很安全;但一万张卡的集群,MTBF 就是 20 小时。
再往下算可用性。假设每次故障平均修复时间 30 分钟(含定位、隔离、重启、恢复检查点),那么一万卡集群的可用性大约是 20 除以 20.5,接近 97.5%。这个数字放在在线服务上勉强能接受,放在训练任务上就很难看——因为一次中断可能意味着几小时的算力回滚。
真正要优化的是平均无故障时间与平均修复时间的比值。提升分子要靠架构加固,降低分母要靠快速检测和自动恢复。我在项目里的体会是,分母的优化空间往往被严重低估:把故障定位时间从 4 小时压到 20 分钟,对整体效率的提升可能比花大代价把 FIT 降一半还明显。
3. 架构级可靠性设计:在哪一层拦截成本最低
设计加固方案时有个基本判断原则:越靠近物理层拦截,成本越高、收益越确定;越靠近软件层拦截,成本越低、代价是延迟发现。聪明的架构是在中间找那个"拦截成本低、发现延迟短"的甜点位置。
3.1 存储层次是第一战场:ECC 的选型与取舍
片上存储是软错误的主要落点,也是加固收益最直接的地方。最基础的是单比特纠错双比特检错码,在 64 位数据上加 8 位校验,开销 12.5%,能纠正任意单比特翻转、检测双比特翻转。这个方案足够覆盖大部分场景,代价是编解码延迟和面积。
但只做单比特纠错在先进工艺下不够。前面说过多比特翻转,如果交织做得好,一个纠错字里最多被打中一位,那单比特纠错就够用。问题是交织会打乱物理布局,增加布线复杂度和延迟。我的经验是,容量大、访问模式随机的共享内存可以接受交织带来的布线代价;而对延迟极度敏感的寄存器堆和小容量缓存,往往选择牺牲容量或直接用更高强度的保护。
HBM 这类高带宽外部存储是另一个重点。它内部有片上纠错,链路上还有循环冗余校验和重传,看起来保护很完整。但实际部署时我建议重点核查三件事:片上纠错是否真的开启且阈值配置合理、链路重传是否会导致明显的带宽抖动、以及巡检机制是否在跑。巡检的意义在于主动扫描内存,把"潜伏的单比特错误及时纠正",防止它累积成双比特错误。很多团队忽略这一点,结果就是单比特纠错能力被浪费掉了——因为没有巡检,单比特错误会一直待在那里,等到第二个比特翻在同一条纠错字上,就变成了不可纠正错误。巡检频率需要权衡带宽占用和累积风险,我的经验值是完整扫描周期控制在几小时量级比较合理。
3.2 计算单元的容错:不是所有加法器都值得做三模冗余
计算逻辑的加固有个经济学问题。全芯片三模冗余意味着三倍面积、三倍功耗,而且三模表决器本身也会引入延迟和新的失效点,实际收益远没有理论值那么漂亮。所以现实中几乎没人对整颗 AI 芯片做全冗余。
更务实的做法是分层加固。控制路径——指令译码、状态机、调度器、地址生成——这些逻辑面积占比小但错了就全乱套,可以用双模冗余加比较器,或者干脆锁步执行,代价可以接受。数据路径——大量并行的乘加阵列——面积占比 80% 以上,用冗余不现实,转而依赖算法级手段。
算法级手段里最有效的是校验和与重算。矩阵乘法天然适合做行列校验:给输入矩阵附加校验行和校验列,一次乘法就能同时得到结果的校验值,与预期值比对即可发现计算过程中的错误。开销通常在 10% 以内,检测覆盖率相当高。这套方法在容错计算领域是老技术,但用在 AI 加速器上特别合适,因为它的计算模式高度规整。
另一个经常被低估的手段是结果比对。同一次前向计算用两种不同的累加顺序各算一遍,结果应该在浮点误差范围内一致。这个方法不需要额外硬件,只需要软件调度上多花一点算力,适合用在推理这种对延迟不极端敏感的场景。训练场景里我用得更多的方式是检查点重算——把检查点之后的若干步重新算一遍,与原始结果比对,差异超过阈值就判定出了问题。代价是算力翻倍,所以只在可疑时段启用。
3.3 互连与片上网络:链路可靠性决定集群能不能撑住
单卡内部的片上网络和卡间的互连,在可靠性上的地位经常被排在存储之后,我觉得这是个误区。多卡训练里,梯度同步是全网状的通信,一条链路出问题可能导致整个通信组超时,损失的是全部卡的算力。
链路层的基本手段是循环冗余校验加重传。发送端算校验、接收端验证、出错就请求重发。这套机制本身很成熟,真正容易出问题的是重传与流控的交互。基于信用量的流控在丢包重传时,如果信用返还路径和重传路径出现竞争,极端情况下会触发死锁。我在一个模拟项目里就遇到过类似的场景:链路误码率在高温下升高,重传变多,信用返还延迟增加,发送端误判接收端缓冲耗尽,双方互相等待,最后靠超时机制才解开,但那一次已经是整组训练卡死了二十分钟。解决办法是给控制通路和数据通路做物理或虚拟通道隔离,保证控制信息在任何拥塞情况下都能通过。
片间互连还要考虑前向纠错编码的强度选择。编码越强,纠错能力越好,但延迟和带宽开销也越大。加速器之间的链路通常工作在很高的速率上,延迟敏感,所以多数方案选择"轻量前向纠错 + 重传兜底"的组合。这个组合的关键参数是纠错码能纠正几位、重传的超时阈值怎么定。超时定太短会频繁误触发重传,定太长则故障恢复慢。我的经验是按链路的往返延迟加上三倍标准差来定,同时保证重传缓冲区足够深。
3.4 RAS 控制平面:把散落的错误信息组织成可决策的信号
前面讲的都是"检测和纠正",但检测出来之后怎么办,才是真正体现架构功力的地方。一颗成熟的 AI 芯片需要一套完整的 RAS 控制平面,做四件事:分级、记录、隔离、降级。
分级是把错误按严重程度分类。能纠正的单比特错误算一类,可纠正但频次异常的算一类,检测到但纠正不了的算一类,会导致整片失效的算一类。分级的意义在于不同级别触发不同响应:第一类只计数不动作,第二类超过阈值就标记对应内存页或缓存行不可用,第三类触发隔离或重启,第四类直接报致命错误。
记录是很多人做得最敷衍的一环。只记"某类错误发生了 37 次"没有意义,必须记录地址、错误码、时间戳、当时的温度与电压、触发时的指令指针。有了这些,才能判断是随机分布还是有热点区域,是温度相关还是与特定访存模式相关。
隔离和降级是最后的手段。隔离的粒度要尽可能细——能隔离到一个缓存行就别隔离整个 bank,能关一个计算簇就别关整颗芯片。我在一个模拟项目里做过对比:把故障隔离粒度从"整片下线"细化到"按内存分区下线",集群在同等故障率下的可用算力提升了将近 8%。这个数字看起来不大,但放到万卡规模上就是几百张卡的产能。
4. 系统级兜底:架构解决不了的部分交给软件
再强的架构加固也不可能把故障率降到零,一定有一批错误会穿透所有硬件防线。这时候系统层的设计就成了最后一道闸门。这一节讲的三件事,是我认为投入产出比最高的。
4.1 检查点策略:频率不是拍脑袋定的
检查点是训练任务的事实标准,但检查点该多久存一次,绝大多数团队是靠感觉。其实这个问题有明确的最优解。
设检查点写入耗时 C,系统平均无故障时间为 M,那么存在一个使总开销最小化的检查点间隔。直观理解是:存得太频繁,写入本身的开销占比高;存得太稀疏,每次故障都要回滚很长一段。在故障率相对稳定的假设下,最优间隔约等于 2 倍 C 乘以 M 再开平方。
代入具体数字。假设单次检查点耗时 5 分钟,集群 MTBF 是 24 小时(86400 秒),那么最优间隔约等于根号下 2 乘 300 乘 86400,约等于 7200 秒,也就是 2 小时。如果 MTBF 掉到 8 小时,最优间隔缩短到约 70 分钟。这个公式的价值在于,它把"要不要加密检查点"从一个经验判断变成了一个可计算的问题:当集群故障率上升时,间隔必须跟着缩短,否则回滚损失会快速吃掉收益。
除了频率,还有两个优化方向值得做。分层存储:先把检查点快速写到本地高速存储,再异步搬到远端持久化,把写入延迟从分钟级降到秒级,公式里的 C 直接变小,最优间隔随之拉长。增量检查点:只写变化的部分,同样能显著降低 C。这两个手段叠加,实际能把有效检查点开销压到原来的三分之一左右。
4.2 热设计:温度不只是性能问题,更是可靠性问题
散热设计在很多人眼里是"别让芯片降频"的问题,其实它对可靠性的影响更深远。前面讲过,结温每升高 10 到 15 度,多数老化机理的退化速率接近翻倍。一颗常年工作在 85 度而不是 70 度的芯片,两年后的参数漂移可能相当于别人四年。
架构层面能做的是温度感知的调度。芯片上分布多个温度传感器,调度器据此调整各计算簇的负载,避免局部热点。这个机制听起来简单,实现时有两个坑。一是传感器本身的精度和响应速度,采样太慢跟不上负载变化,采样太快又会产生大量中断。二是调度的抖动,如果热点判定阈值定得太敏感,负载会在簇之间反复迁移,反而造成额外的热循环。我的经验是给迁移加一个滞回区间,温差超过 8 到 10 度才触发迁移。
系统层面则是散热链路的可靠性。风扇、泵、冷板、导热界面材料都是有寿命的部件,而且它们的失效往往不是突发的,是效率缓慢下降。所以除了温度监控,还需要监控"同等负载下的温度变化趋势"。如果发现在相同功耗下温度逐月上升,基本可以判定散热链路在劣化,这时候主动维护比等到过温保护触发要好得多。
4.3 电源完整性:最容易被当成"软件 bug"的那类故障
大电流负载的瞬变是 AI 加速卡面临的一个特殊挑战。计算阵列从空闲切到满载,电流变化率极高,供电网络上的寄生电感会感应出电压跌落。如果跌落超过时序裕量,触发器可能采到错误值,而这种错误在功能上表现为随机的、不可复现的数值异常——最容易被误判成软件问题。
我经历过一次非常典型的排查。某个 kernel 在特定输入尺寸下偶尔产生错误结果,重跑十次可能只复现一次。查了两周软件无果,最后用示波器抓供电轨才发现,那个输入尺寸恰好让计算阵列的启动节奏形成了周期性的电流尖峰,与供电网络的谐振频率接近,电压波动被放大了。解决办法是在调度上加一个错峰启动的约束,把同时启动的计算簇数量限住,让电流上升沿变缓。
架构上应对这类问题的常规手段是去耦电容的合理布局和电压跌落检测电路。去耦电容要靠近负载放置,中间的电感和电阻越小越好,这点在版图阶段就要规划,后期改不动。电压跌落检测则是在关键位置放比较器,一旦检测到超阈值的跌落就触发流水线冲刷重算,把"静默错误"转成"可恢复的显式事件"。这个设计的价值极高,因为它的成本只有几个比较器和一点控制逻辑,却能把最难查的一类故障变成最容易处理的一类。
5. 验证与评估:可靠性是测出来的,不是想出来的
设计完一套加固方案,怎么证明它有效?这是我在项目里花时间最多的部分。答案只有一个:故障注入。没有经过注入验证的可靠性设计,本质上是一种信仰。
5.1 故障注入框架的四个必备要素
一个能用的注入框架需要四样东西:故障模型、注入点、工作负载、结果分类。
故障模型定义"注入什么"。常见的有单比特翻转、多比特翻转、固定为 0 或 1、路径延迟增加、链路丢包。模型的选择要贴合实际机理,不能图省事只做单比特。
注入点定义"注入到哪"。寄存器堆、共享内存、缓存、控制状态机、互连链路,覆盖越全越好。我的做法是先按架构脆弱因子排序,优先覆盖高脆弱区域,这样在有限的注入次数里能覆盖最多风险。
工作负载定义"在什么情况下注入"。这是个容易被忽略但极其关键的点。用一个小矩阵乘的微基准测出来的覆盖率,跟真实训练负载下的覆盖率可能差好几倍,因为真实负载会访问更多的状态、走更多的分支。能用真实负载就别用微基准。
结果分类定义"怎么判断这次注入的影响"。至少分四类:被纠正、被检测但不可纠正、静默错误、无影响。其中静默错误的比例是核心指标,所有加固设计的目标都是把这个比例压下去。
5.2 加速老化实验的参数外推
老化验证没法等两年,只能加速。常用手段是提高温度、提高电压、提高开关频率,然后在加速条件下测退化量,再用模型外推到正常工作条件。温度项通常用阿伦尼乌斯模型,电压项用艾林模型或幂律模型。
这里有个容易犯的错误:加速得太狠,引入了正常工作下不会出现的新失效模式,测出来的数据就没意义了。所以加速倍率要控制在一个合理范围内,通常温度不超过额定最大结温,电压不超过额定值的 1.2 倍,并且至少做两组不同加速条件的实验来验证模型的一致性。只有两组数据的退化趋势在换算到同一基准后能对齐,外推结果才可信。
5.3 指标口径要统一,否则没法跨团队对话
最后一点经验:可靠性指标必须有统一口径,否则架构团队、运维团队、业务团队说的根本不是一回事。我建议至少明确这几个定义——FIT 值统计的器件范围包含哪些、是否含封装和板级、静默错误的统计口径是"注入实验中未检测到的比例"还是"生产环境中事后定位到的比例"、可用性是按整卡还是按作业完成率计算。
| 指标 | 定义口径 | 常见误用 |
|---|---|---|
| FIT | 每十亿器件小时失效次数,需注明统计范围 | 不同范围直接横比 |
| 静默错误率 | 未检测到的错误数 / 总注入数 | 与生产事故率混为一谈 |
| 作业完成率 | 成功完成作业数 / 提交作业数 | 未剔除用户主动取消 |
| 有效算力利用率 | 有效计算时间 / 总挂钟时间 | 忽略回滚造成的时间损失 |
6. 常见问题与排查技巧实录
这一节是我这几年攒下来的排查经验,按故障表现组织,遇到对应症状可以直接对照。
6.1 训练 loss 突然跳变或出现 NaN,怎么快速定位
第一步永远是判断是单卡问题还是全局问题。多卡训练时,先看 loss 曲线是不是所有数据并行分支同时异常。如果只有一路异常,问题大概率在那张卡或那条链路上;如果全部同时异常,更可能是通信或全局状态的问题。
第二步看异常发生前的窗口。我习惯把发生前 500 到 1000 个 step 的梯度范数、参数范数、激活值范围都拉出来看。常见模式有两种:梯度范数在异常前几十步开始缓慢爬升,那是数值稳定性问题,比如某个归一化层的方差逼近零;梯度范数一直是正常抖动,然后在某一步突然爆掉,那更可能是硬件层面的静默错误。
第三步做针对性复现。从上一个检查点重启,用相同的随机种子和数据顺序跑。如果能复现,就是软件问题;如果换一张卡就不复现,基本可以锁定硬件。这一步的关键是要保留完整的数据加载顺序和随机数状态,很多团队为了省事不存这些,导致永远无法复现。
第四步是隔离验证。把可疑卡下线,跑一个长时间的算力自检程序,同时对它的内存做完整巡检。如果巡检报告里出现了纠正错误的累积,基本就确认了。
6.2 静默错误的定位手法
静默错误最难的地方是它不留下时间戳。我的做法是把检测点前移,不等结果异常再查,而是在训练流程里插入周期性的结果比对。
具体做法是每隔固定的步数,用两条不同的计算路径(比如不同的累加顺序、不同的并行切分方式)各算一遍前向,比对输出。差异超过浮点误差阈值就报警。这套机制会消耗额外的算力,所以我一般只在故障高发期或新硬件上线初期启用,稳定后关掉。
另一个有效手段是端到端校验和。在关键数据结构的头部附加一个校验值,每次读写都验证。这需要软件栈配合,改造成本不低,但收益很实在:它能把"三周后才发现"缩短到"下次访问就发现"。
6.3 常见问题速查表
| 现象 | 可能原因 | 排查动作 | 处置 |
|---|---|---|---|
| 单卡 loss 持续偏高无报错 | 内存或链路静默错误 | 完整内存巡检、链路误码统计 | 隔离分区,替换部件 |
| 特定 kernel 偶发结果错误 | 供电瞬变或时序违例 | 抓供电轨波形、查负载启动节奏 | 错峰调度,加去耦 |
| 高温时通信超时增多 | 链路误码率随温度上升 | 统计温度与误码相关性 | 降频或加强散热 |
| 长时间运行后频率自动下降 | 老化导致时序裕量不足 | 读老化传感器数据 | 接受降频,规划更换 |
| 检查点写入越来越慢 | 存储链路退化或碎片化 | 监控写入延迟趋势 | 分层存储,增量写入 |
| 随机重启无错误日志 | 供电跌落或致命错误未记录 | 检查供电监测与日志完整性 | 补全 RAS 日志链路 |
6.4 几条踩过坑才明白的心得
别迷信供应商给的 FIT 数字。那是实验室条件下的典型值,实际部署环境的温度、海拔、负载画像都不一样。我的做法是在自己的环境里跑一段时间的统计,用实际故障数反推有效 FIT,通常比标称值高不少,按实测值做容量规划更靠谱。
日志的完整性比日志的详细程度更重要。很多设计把日志写得很详细,但故障一旦发生,日志还没来得及刷到持久存储就断电了,等于没有。所以关键错误必须走同步落盘路径,宁可牺牲一点性能。
降级策略要提前演练。我见过太多系统,故障隔离逻辑写得很完善,但从来没跑过,真出事的时候隔离动作本身引入了新的问题。定期人工注入故障,走一遍完整的隔离降级流程,比写一百页设计文档管用。
别把可靠性做成一次性项目。硬件上线时的故障率通常是最低的,随着时间推移,老化、散热劣化、固件漂移会让故障形态不断变化。要建立长期的故障数据采集和分析机制,按季度回顾一次故障分布,根据实际数据调整加固重点。
最划算的投资往往在可观测性上。加一个温度传感器、加一条错误计数通路、加一段链路误码统计,成本几乎可以忽略,但它们决定了你出问题时是花二十分钟定位还是花两天。我在项目里推动的第一件事就是补全错误上报链路,收益比任何一项加固设计都直接。
我个人在实际操作中的体会是,AI 硬件的可靠性从来不是靠某一项技术解决的,它是架构加固、系统兜底、运维可观测性三层叠加出来的结果。硬件的加固决定了故障率的下限,软件的容错决定了故障影响的边界,而可观测性决定了你每次能从故障里学到多少。三者缺任何一环,另外两环的投入都会大打折扣。如果让我给刚接触这个方向的同行一个建议,那就是先别急着研究加固方案,花两周时间把现有系统的错误日志链路理顺、把故障分类统计做出来,你对问题的理解会比读十篇论文都扎实。