☰
Prometheus+DCGM Exporter打造GPU监控体系:智能告警与实战
2026/9/26 18:34:45 网站建设 项目流程

上个月我帮团队把一台8卡NVIDIA训练服务器的GPU监控完整重做了一遍:从原来Zabbix加自定义脚本的土方案,切换到Prometheus + DCGM exporter + Grafana + Alertmanager这套体系。之所以动手,是因为网上聊prometheus监控GPU使用率的教程不少,但多数贴一段配置就完事,真正关键的智能告警阈值怎么定、误报怎么压、指标到底怎么解读,很少有人说透。这篇就把我自己实际跑通全链路的过程整理出来,适合正在搭GPU集群监控、或者已经被GPU告警轰炸到麻木的人参考。

先说结论:GPU监控的难点从来不在采集,而在两个地方——一是选对采集器和指标,二是把告警阈值做成能适配训练场景的复杂节奏。这篇会按采集链路搭建、核心指标解读、可视化配置、智能阈值设计、踩坑记录的顺序展开,每一段都有能直接抄走的配置和PromQL。

1. 把GPU监控做成体系:方案选型与整体链路

1.1 先搞清楚监控什么:GPU指标不是只有利用率

我见过很多初学监控的人,上来就在Grafana拖一个"GPU Utilization"面板,看到数字80%就觉得完事。但真正跑过大模型训练和推理服务的人知道,GPU指标是分层的。简单分成四类:

  • 算力类指标:SM占用率、GPU利用率、MIG设备利用率。这类指标反映芯片计算核心的忙碌程度,但利用率高不代表效率高——比如数据加载慢,GPU也能保持高占用率在等待;
  • 显存类指标:显存使用量、剩余量、带宽利用率、内存拷贝速率。训练场景里显存泄漏是最常见的故障源,OOM前往往有规律性的显存爬坡;
  • 物理类指标:核心温度、显存温度、功耗、风扇转速、电压。这类指标直接影响硬件寿命,A100/H100这些卡对温度极其敏感,超过阈值会主动降频;
  • 链路类指标:PCIe收发速率、NVLink带宽、XID错误。多卡通信和分布式训练里,这些指标比利用率更能反映瓶颈。

所以方案设计的第一步不是装软件,而是先列一个"我要为哪类问题负责"的清单。我们团队的核心诉求是两条:一是训练任务出问题能及时发现,二是别让GPU因为过热或显存耗尽而悄悄掉点。这个诉求决定了采集器选型、指标保留周期和告警规则的侧重点。

1.2 三款主流采集器怎么选

Prometheus生态里没有官方专门为NVIDIA GPU写的采集器,但可选方案不少,我实际对比过三款:

采集器指标丰富度部署难度适用场景
DCGM exporter高(SM、NVLink、XID、功耗全都有)中NVIDIA官方推荐,混合算力集群首选
node_exporter + nvidia-smi textfile低(只有核心几个计数)低快速验证、单卡测试、不想多装容器
nvml-exporter中(NVML库直接采集)中需要轻量且不想依赖DCGM容器的场景

我当时直接选了DCGM exporter。原因不复杂:NVIDIA官方维护,指标命名规范,最基本的好处是DCGM_FI_DEV_XID_ERRORS这个字段能直接抓到GPU报错事件,这是排查硬件故障的金钥匙。node_exporter的textfile方式胜在简单,但采集脚本要自己写,而且多卡节点的标签容易出岔子。

部署方式上我选了Docker运行DCGM exporter,因为不用在宿主机上装额外的Python依赖或者编译NVML绑定,宿主机只需要有NVIDIA驱动和nvidia-container-toolkit。整条监控链路最终是这样的:

  • GPU服务器上的DCGM exporter采集指标,暴露一个/metrics端口;
  • Prometheus定时抓取这个端口,把指标存进TSDB;
  • Grafana连接Prometheus做可视化大屏;
  • Alertmanager接收Prometheus的告警规则推送,负责去重、分组和通知到钉钉/企业微信。

这个链路的好处是每个环节职责单一。出问题的时候,先查exporter有没有数据,再查Prometheus有没有抓取,最后才查告警有没有被规则拦截——排查路径非常直。

2. 一步步搭建采集链路:从exporter到Prometheus

2.1 环境准备与基础依赖

先说环境。这套方案对GPU服务器有个硬性要求:必须装好NVIDIA官方驱动,然后装nvidia-container-toolkit,否则DCGM exporter的容器起不来。我用的是Ubuntu 22.04 + NVIDIA驱动535 + CUDA 12.2的组合,宿主机上还跑着PyTorch训练任务。

验证环境就两条命令:

nvidia-smi # 能输出GPU列表就说明驱动OK
docker run --rm --gpus all nvidia/cuda:12.2.0-base-ubuntu22.04 nvidia-smi

第二条命令如果报could not select device driver这类错误,说明nvidia-container-toolkit没装好或者Docker配置有问题。这个前置不做干净,后面exporter起不来很容易让人误判成Prometheus配置的锅。

另外建议给exporter留一个独立端口,不要和业务混用。我用的端口规划是:

  • 9400:DCGM exporter
  • 9100:node_exporter(系统基础指标,CPU/内存/磁盘,搭配GPU告警做联合判断)
  • 9090:Prometheus自己
  • 3000:Grafana

2.2 用DCGM exporter采集GPU指标

DCGM exporter的启动参数比想象中简单。官方镜像名是nvidia/dcgm-exporter,我使用的启动命令是:

docker run -d --gpus all \ --name dcgm-exporter \ --restart=always \ -p 9400:9400 \ nvidia/dcgm-exporter:3.3.5-ubuntu22.04

启动后直接访问http://localhost:9400/metrics,能看到类似这样的输出:

dcgm_gpu_utilization{gpu="0",UUID="GPU-xxxxx",device="nvidia0",modelName="NVIDIA A100-SXM4-40GB"} 95.0 dcgm_gpu_temp{gpu="0",UUID="GPU-xxxxx",device="nvidia0",modelName="NVIDIA A100-SXM4-40GB"} 65.0 dcgm_gpu_fb_used{gpu="0",UUID="GPU-xxxxx",device="nvidia0",modelName="NVIDIA A100-SXM4-40GB"} 37888.0 dcgm_gpu_fb_total{gpu="0",UUID="GPU-xxxxx",device="nvidia0",modelName="NVIDIA A100-SXM4-40GB"} 40960.0

看到这些指标就意味着采集链路通了。我建议第一次先手动加几个sample进去,确认标签结构没问题再上Prometheus。

有一个容易忽略的点:默认DCGM exporter会暴露一大批指标,实际告警用得上的只有十几个。指标太多不是坏事,但要留意Prometheus抓包大小和存储膨胀。我对DCGM默认启用的指标做了裁剪——通过-f /etc/dcgm-exporter/dcgm-metrics.csv指定要采集的字段集合,保留利用率、温度、功耗、显存使用、SM时钟、PCIe收发、XID错误这些关键项就够了。这个文件里每一项的格式是# Prometheus metric name, help text, DCGM field ID,照着官方文档抄就行。

2.3 Prometheus抓取配置与验证

Prometheus的scrape配置同样不算复杂。如果有多台GPU服务器,可以给每个exporter的job打上一个机架和集群标签,方便后面做分组聚合:

scrape_configs: - job_name: 'nvidia_gpu' scrape_interval: 15s scrape_timeout: 10s static_configs: - targets: ['192.168.1.10:9400', '192.168.1.11:9400'] labels: cluster: 'train-prod' rack: 'rack-a'

这里我要特意说一下scrape_interval的选择。GPU利用率这类指标是高频变化的,30秒抓一次也能看个大概,但做告警判断时窗口太粗容易漏掉瞬时尖峰。15秒是比较平衡的值,即不会让TSDB膨胀太快,也能捕捉到大多数训练任务的波动。

配置好了之后,在Prometheus的Targets页面看到UP状态,再输入dcgm_gpu_utilization能拉出数据,就说明采集链路已经OK。我自己会在这一步顺便验证一下status页面的TSDB Status,确认样本摄入量没有异常飙升。

3. 读懂指标才是关键:可视化与核心指标解析

3.1 黄金指标:哪些GPU数据值得上大屏

采集器装好之后,一不留神就会陷入"什么指标都往面板上堆"的误区。一个大屏放二十个图,最后每个图都没人看。我实际用下来,GPU监控真正值得长期盯的只有这几个黄金指标:

  • GPU利用率(dcgm_gpu_utilization):反映计算单元忙碌程度,用来快速判断任务是否在跑;
  • 显存使用率(dcgm_gpu_fb_used / dcgm_gpu_fb_total):训练和推理场景的"容量水位线",显存爆了的后果是OOM杀进程;
  • 温度(dcgm_gpu_temp):高温会触发降频,影响训练速度,还会损伤硬件;
  • 功耗(dcgm_gpu_power_usage):判断任务负载是否接近TDP上限,也能侧面反映供电是否异常;
  • SM时钟(dcgm_gpu_sm_clock):这是一个容易被忽略的真相指标。GPU利用率高但SM时钟掉到很低,说明被Power Cap或温度限制压住了,这是在"虚假忙碌";
  • PCIe RX/TX速率(dcgm_gpu_pcie_rx_bytes、dcgm_gpu_pcie_tx_bytes):分布式训练里数据搬运如果打到PCIe瓶颈,单卡利用率再高也没用。

这六个指标组合起来,用一个很朴素的判断逻辑就能定位90%的问题:先看利用率是否异常,再看显存是否逼近上限,接着瞄温度功耗,最后查SM时钟确认没有被降频。我是按这个逻辑来设计Grafana仪表盘的,而不是按指标类型随手堆图。

3.2 用PromQL算出真正想看的数据

Grafana面板展示最多的量有两类:瞬时值和窗口聚合值。瞬时值直接查指标名就行,但窗口聚合才是告警和复盘时真正依赖的。我自己常用的PromQL有这么几条:

计算最近5分钟的GPU平均利用率(按GPU实例分组):

avg_over_time(dcgm_gpu_utilization[5m])

计算显存使用百分比:

100 * dcgm_gpu_fb_used / dcgm_gpu_fb_total

找出所有显存使用超过90%的GPU,并且带上节点名:

(100 * dcgm_gpu_fb_used / dcgm_gpu_fb_total) > 90

计算最近1小时内的显存增长趋势,这个对显存泄漏检测特别有用:

deriv(dcgm_gpu_fb_used[1h])

我在实际面板里还会用max by (instance)或者topk来做多卡节点的汇总。比如在一个8卡节点上,我想看最忙的那张卡的利用率:

topk(1, dcgm_gpu_utilization)

这种聚合在"分布式训练某个节点掉队"的排查场景里非常关键。因为很多时候不是整节点都慢,而是某张卡被其他任务抢了算力或者网络排队卡住。

3.3 Grafana仪表盘实测建议

Grafana这边我直接推荐在官方面板库搜索"NVIDIA DCGM",排名靠前的成熟模板比自己从零拖图快得多。不过模板导入之后不要直接拿来做告警依赖,一定要做一个动作:把面板的变量改成自己的instance、gpu标签命名。很多模板把gpu="0"这种标签写死,多卡节点的第二张卡就是不显示,查了半天还以为是采集问题,其实是面板变量写法没对上。

另外一个Grafana使用经验:把同一个指标分别做成"当前值"和"过去24小时对比"两个面板。当前值面板在前一天面板下方,一上一下对照着看,才能发现"昨晚8点开始功耗突然低了30%"这种跨天异常。这种时间维度的对比,比单看一个绝对值有用得多。

如果想把大屏做到"一眼看出问题"的程度,试着把颜色阈值设成语义化的:利用率低于20%设成黄色(代表资源空转),高于90%设成红色(代表高负载),中间用绿色。这里有个反直觉的点——GPU利用率高不一定是坏事,所以不要一看到90%就署名为异常,要结合业务时段来判断。

4. 智能告警阈值:别再用一拍脑袋的固定数值

4.1 固定阈值为什么会误报漏报

说到告警阈值,团队里最常见的做法是:GPU利用率低于10%就告警,温度超过85度就告警,显存超过95%就告警。这类固定阈值在只跑单一业务的小集群里勉强能用,但在真实训练环境里问题非常大。

举几个我踩过的例子。一次凌晨跑数据分布式数据加载,因为数据读取卡IO,GPU利用率掉到接近0,告警狂响,值班的人爬起来发现没有任何故障,只是上游生成训练数据的任务还没准备好。还有一次多卡并行训练,有张卡被另一个团队的任务占用了,利用率被拉高,但温度也随之升高,两条告警同时弹出,最后发现是资源分配冲突,不是硬件问题。

这背后的本质问题是:GPU的工作状态天然是"锯齿形"的。训练任务有前处理、数据加载、梯度同步、模型保存阶段,不同阶段利用率从0到100来回跳,温度功耗也跟着波动。单点固定阈值对这类时序数据几乎必然产生误报。

4.2 动态基线与预测告警的实际做法

真正有效的"智能阈值",我理解不是上一套机器学习平台,而是让告警规则具备"时间上下文"和"趋势判断"能力。具体做三层:

第一层,用窗口均值代替point值。告警表达式里不用dcgm_gpu_utilization < 10,而是用avg_over_time(dcgm_gpu_utilization[10m]) < 10。这一步就能滤掉大部分瞬时抖动。

第二层,加"持续时长"和"波动范围"约束。Prometheus规则里的for字段用来避免短暂波动触发告警,设定为for: 10m表示连续10分钟满足条件才告警。再加一个波动约束,比如要求利用率不仅低,还要在窗口内保持稳定,防止训练任务本身就有规律性的低利用率阶段被误报。

第三层,用预测函数做趋势告警。最常用的是predict_linear,它用历史数据线性拟合未来趋势。针对显存泄漏问题,可以这么写:

predict_linear(dcgm_gpu_fb_used[1h], 3600) > dcgm_gpu_fb_total * 0.95

这条表达式的含义是:用过去1小时的显存趋势外推未来1小时,如果预计会超过总显存的95%,就提前告警。实际效果比等到显存真的到95%再告警要好很多——训练任务出现OOM之前,这种预测往往能提前20到40分钟给出信号。

4.3 多条件组合与Alertmanager告警路由

第三层告警优化的思路是组合条件。单一指标告警容易误报,两个指标联合就能准确得多。比如:

  • 只有当温度>85且SM时钟下降超过10%时才告警,这能区分"真过热"和"单纯功耗高";
  • 只有当显存使用>92%且还在持续增长时才告警,这能识别显存泄漏而不是一次性加载大模型;
  • 只有当GPU利用率<10%且节点CPU负载>8时才告警,这能识别数据加载瓶颈而不是空闲。

Prometheus告警规则文件里实际的一条长这样:

groups: - name: gpu_alerts rules: - alert: GPUMemoryLeakPredicted expr: predict_linear(dcgm_gpu_fb_used[1h], 3600) > on(gpu, instance) dcgm_gpu_fb_total * 0.95 for: 5m labels: severity: critical annotations: summary: "GPU {{ $labels.gpu }} 预测将发生显存耗尽"
Alertmanager这边的路由也建议好好设计。我的做法是把告警按集群和严重级别分组:critical级别的直接通知到值班群并电话强提醒,warning级别的按小时聚合发摘要。再用抑制规则避免雪崩——比如某台机器已经触发了"节点宕机"告警,那么该节点上所有GPU相关告警在窗口内自动抑制,不让同一件事刷屏。 这个组合式告警的效果,是我这套方案里最值得复制的部分。以前一晚上可能收到30条GPU告警,里面一半是误报;调整完之后,一周能数得过来的告警条数,且每一条基本都能对应到真实故障或者风险信号。 ## 5. 实测踩坑记录与问题排查速查表 ### 5.1 部署阶段最常翻车的几个点 整个搭建过程不是一次就顺的,踩过的坑里印象比较深的有四个: 第一个坑是DCGM exporter容器起不来,日志报`Failed to initialize NVML: Could not find NVML library`。排查到最后发现宿主机只装了NVIDIA驱动,没有装`nvidia-container-toolkit`,Docker无法把驱动透传到容器里。解决办法是按NVIDIA官方文档装好toolkit后重启Docker,再重新起容器。 第二个坑是Prometheus的target页面显示`connect refused`。一开始以为exporter挂了,curl一下9400端口发现是本机正常、外部不通,最后定位是云安全组没放行9400端口。这种网络层问题在自建机房和云环境里表现不同,自查顺序永远是先curl,再查防火墙,最后才看配置。 第三个坑是Alertmanager收不到webhook。Prometheus规则已经显示为`Pending`和`Firing`,但钉钉机器人没有消息。检查之后发现Prometheus根本没配`alertmanagers`地址,或者配了但`--web.listen-address`端口写错。这个属于基础配置遗漏,但特别容易忽略。 第四个坑是多卡节点的`gpu`标签在Grafana面板里全部显示空白。问题出在DCGM exporter的tag mapping——不同版本对GPU编号字段的暴露方式有差异,旧模板用了`gpu_id`,新版本数据里只有`gpu`。Grafana变量改成实际存在的标签名就好了。 ### 5.2 告警骚扰和漏报的处理思路 告警骚扰是另一个长期问题。要减少骚扰,最有效的不是调阈值,而是把告警的时效性设计好。我有了几个经验: 一条告警的`for`字段,我建议至少10分钟。GPU利用率低这一类的瞬时波动,在10分钟窗口内会被过滤很多。不过温度告警的`for`不应该这么长,因为高温对硬件的损伤是持续的,连续3到5分钟超过阈值就值得看一眼,等10分钟可能已经因为降频影响了训练进度。 另一个想法是"告警分级而不是一刀切"。显存超过92%设为warning,超过95%且还在增长设为critical。分级之后,值班的人才有精力真正看critical,不然每天都是狼来了。 漏报的情况恰恰相反,常见原因是窗口聚合太狠。我曾经用`avg_over_time(dcgm_gpu_utilization[30m]) < 10`来告警,结果某个真的出现故障的节点,因为故障前30分钟内利用率有高有低,平均值被稀释到没有触发。调整成`max_over_time(dcgm_gpu_utilization[10m]) < 10`之后才恢复敏感度。所以聚合窗口的选择要跟业务的"故障表现"对齐,不能一个窗口打天下。 ### 5.3 排查问题速查表 把这段时间的经验整理成一张速查表,比较常用的问题基本都能在上面对号入座: | 现象 | 可能原因 | 排查命令/方法 | | --- | --- | --- | | exporter起不来,日志有NVML错误 | 缺nvidia-container-toolkit | `docker run --rm --gpus all nvidia/cuda:12.2.0-base-ubuntu22.04 nvidia-smi` | | Prometheus target DOWN | 端口未放行/服务未监听 | `curl http://<node>:9400/metrics`,再查防火墙 | | 指标有值但Grafana面板不显示 | 面板变量标签名对不上 | 在Explore里查`dcgm_gpu_utilization`,确认可用标签 | | 告警规则Pending但不Firing | `for`字段还没满足 | 直接查规则状态,观察`for`持续时间 | | Alertmanager收不到消息 | 没配置`alertmanagers`地址 | 检查prometheus.yml里的alertmanagers和默认端口9093 | | 温度高但SM时钟拉不满 | 降频保护触发 | 查`dcgm_gpu_sm_clock`,再看`dcgm_gpu_power_usage` | 这套GPU监控体系我在生产环境跑了两周多,最大的感受是:工具链选型占两成,剩下的功夫都在指标理解和告警语义设计上。DCGM exporter提供的原始指标只是原材料,真正解决"显卡挂了没人知道""显存泄漏发现太晚"这些问题,靠的是把PromQL的窗口、预测、组合条件用对。如果你也正准备给自己的GPU集群搭监控,我的建议很直接:先动手把DCGM exporter和Prometheus跑通,然后再花时间把你自己的业务步骤和GPU指标对应起来。阈值和规则永远应该长在你对业务的判断上,而不是长在模板里。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询