GPU 掉卡告警怎么做(一):count<8 和 XID 失灵,以及'冻住不动'的误报坑
一句话:给 GPU 集群做"掉卡"告警,我先想用"卡数变少"和"报错码"来发现坏卡,结果都失灵;改用"指标冻住不动"来判断,又被"其实是没采到数据"坑了误报;最后发现把测试环境排掉,告警就干净了。
下面讲清这三步。文中 IP、Pod 名均为占位。
环境
- 每节点 8 张 GPU,跑在 k8s 上;
dcgm-exporter采集 GPU 指标 → Prometheus;- Nightingale(n9e)按 PromQL 判定 + 飞书告警。
"掉卡"指:某张 GPU 挂死、业务用不了它,但节点本身还是正常的。
一、最直觉的两个办法,都没用
想法 1:坏卡会从拓扑消失,数节点卡数 < 8。
实际数不出来,原因得从故障类型说起。这次掉卡是 Xid 119/154(GSP 固件超时)。按 NVIDIA/云厂商文档,这类故障里 GPU 并没有从 PCIe 总线掉下去——它在 nvidia-smi 里还在,只是显示 ERR!(排障时实测 gpu7 正是 ERR! 40C,DCGM 采到的温度也冻在 40,对得上)。
卡既然还在驱动的设备列表里,dcgm-exporter 就照样把它当一张在册卡、继续查询并导出它的指标序列(读到的是卡死的最后值,所以每分钟都有新采样点、只是值冻住不变)。而 count(...) by (Hostname) 数的就是"这台还有几条 GPU 序列",8 条一条没少 → 照样数到 8。
要让 count 真掉到 7,得卡从 PCIe 总线上彻底消失才行——比如另一种掉卡 Xid 79(GPU fell off the bus),驱动访问不到它、序列才可能没掉。这也正好解释了为什么不同故障类型、不同集群,表现会不一样。
想法 2:看 XID_ERRORS 报没报错误码。
实际:这次掉卡是 GSP 固件超时,DCGM 根本读不到设备,错误码计数器停在 0——内核日志里明明有 Xid 119/154,但 DCGM 没采到。
注:不是所有掉卡都这样。另一套集群的掉卡是
Xid 79(掉总线),那种 DCGM 能采到,可以直接用XID_ERRORS == 79即时报。能不能靠 XID,取决于具体的故障类型,得拿真实掉卡数据验证,别想当然。
二、换个思路:卡挂了,指标会"冻住不动"
卡挂死时,它的功耗、温度、时钟会冻在最后一个值不动;而活卡哪怕空闲,这三个数也一定在小幅抖动。
所以判定式就是:这三个指标在过去一段时间里标准差都为 0(完全没变化):
stddev_over_time(功耗[15m]) == 0
and stddev_over_time(温度[15m]) == 0
and stddev_over_time(时钟[15m]) == 0
为什么要三个一起?单看一个会误判(空闲卡某个数偶尔也会平一阵);三个一起冻死才是真挂了。
三、坑:"冻住不动",可能是真冻,也可能是没数据
上线前回测,发现有张健康卡被报了"冻结 15 分钟"。把它的原始数据逐分钟打出来一看:
11:38 功耗23W 温度33 <- 有数据,空闲正常
11:44 功耗21W 温度33
11:45 缺 缺 <- 从这里开始,全没数据了!
... (一直缺)
卡根本没冻,是从 11:45 起没采到数据了。 窗口里只剩前面那两个相同的空闲值,标准差当然是 0 → 被误判成"冻结"。
这就是这条规则最大的坑:标准差为 0(值没变化)有两种完全不同的原因——
- 真冻卡:每分钟都采到、每次都是同一个值(数据密);
- 没数据:采集断了,窗口里就剩一两个残留值碰巧相同(数据疏)。
两者都让"标准差=0",但只有第一种是真掉卡。
再查"为什么没数据":不是采集程序挂了,而是那张卡上的 Pod 被重新调度走了——旧 Pod 走之前是空闲的,它最后那几个不变的值,被规则误当成了"冻结"。
四、真正的解法:只盯生产环境
那个制造假冻结的 Pod,是测试(test)命名空间的。这就对上了——测试环境的 Pod 频繁重启、调度,生产环境稳定。
于是给判定式加一个条件:只看生产命名空间(namespace="prod"),把 test 排除掉。重测结果:
- 生产卡 15 天里零误报(健康卡再没出现过长时间"冻结");
- 真掉卡照样能抓到(真掉卡会冻好几个小时)。
一刀就干净了。比起在判定式里堆各种花哨条件,"按命名空间排掉测试环境"才是对症的那一刀。
小坑:有的集群用 kube-prometheus-stack,真实命名空间标签会被改名成
exported_namespace(namespace变成了 kube-system),那种要写exported_namespace="prod"。
五、别纠结告警快几分钟
还有个常被纠结的问题:告警多久能报出来?这条规则的延迟,主要不是"持续确认时间(for)"决定的,而是判定式里那个 [15m] 窗口:
- 卡必须先"冻满 15 分钟",标准差才可能为 0、规则才可能触发——这是绕不开的下限;
for只是再叠加几分钟防抖。for=1分钟总延迟约 16 分钟,for=5分钟约 20 分钟,就差几分钟。
而掉卡是小时级故障(卡一挂就趴好几个小时),你第 16 分钟报还是第 20 分钟报,处理上没区别。所以这条规则要的是"准、不漏",不是"快",别纠结 for 设多小。真想更快,只能把 [15m] 缩短,但窗口越短越容易误判,得不偿失。
小结
- GPU 掉卡别只靠一个信号:
count<8、XID、"冻住不动"各有盲区,必须拿真实掉卡数据回测,别想当然; - "指标没变化"有两种原因:真冻卡(数据密) vs 没采到数据(数据疏)——排查时一定要分清,把原始采样点打出来看缺没缺最直接;
- 冻卡类规则最大的误报源是测试环境 Pod 频繁调度,用
namespace="prod"排掉它,告警立刻干净。
快速参考
判定式(只盯生产、排除测试噪声)
(stddev_over_time(DCGM_FI_DEV_POWER_USAGE{namespace="prod"}[15m]) == 0)
and (stddev_over_time(DCGM_FI_DEV_GPU_TEMP{namespace="prod"}[15m]) == 0)
and (stddev_over_time(DCGM_FI_DEV_SM_CLOCK{namespace="prod"}[15m]) == 0)
# kube-prometheus-stack 的集群改用 exported_namespace="prod"
# for 取 3~5 分钟即可;能采到 Xid 79 的集群另配 XID_ERRORS==79 即时报
排查口诀
- "指标没变化"先分清:真冻卡(数据密) or 没数据(数据疏)——把原始采样点逐分钟打出来看缺没缺;
- 冻卡规则的主要误报源是测试环境 Pod 调度,用
namespace="prod"排掉; - 延迟由
[15m]窗口决定,不是for;小时级故障别过度压延迟。

浙公网安备 33010602011771号