Skip to content

第六部分 GPU 监控与可观测性(第 22~24 章)

第二~五部分完成了环境搭建、虚拟化共享、K8s 调度与高速网络配置。接下来的问题是:这些昂贵的 GPU 跑得好不好?有没有卡快坏了?利用率是不是只有 5% 却在烧电?

本部分带你从零搭建完整的 GPU 监控体系:从单机 nvidia-smi 进阶用法,到 DCGM/dcgm-exporter 指标采集,再到 Grafana 可视化与生产级告警规则,最终交付一套"看得见、告警准、能定位"的监控平台。


第 22 章 nvidia-smi 与监控基础

本章目标

  • 掌握 nvidia-smi 进阶用法:全量查询、自定义字段、CSV 格式化输出与循环采集
  • 正确解读利用率、显存、温度、功耗、降频原因等关键指标,避开常见误区
  • 建立"节点 + GPU + 业务"三层监控体系的全局认知;无 GPU 环境也能模拟学习

22.1 nvidia-smi 进阶用法大全

nvidia-smi(NVIDIA System Management Interface)是 GPU 运维的"瑞士军刀"。前面章节我们用过它的默认输出,本节深入它的两大高级模式。

22.1.1 -q:全量信息查询

bash
# 查询所有 GPU 的全部信息(输出很长,适合存档或交给 AI 分析)
nvidia-smi -q
nvidia-smi -q -i 0                       # 只看某一张卡(-i 指定索引)
nvidia-smi -q -d TEMPERATURE,POWER,CLOCK,ECC   # 只看指定段落

-q 的输出按段落组织,运维中最常看的段落:

段落关注点
Product Name / VBIOS Version型号与固件版本
Persistence Mode是否开启持久模式(生产必须 ON)
Power Readings当前功耗 / 功耗上限
Clocks / Clocks Event Reasons当前时钟与降频原因(见 22.2)
TemperatureGPU 核心温度、显存温度、降频阈值
ECC Errors / Retired PagesECC 错误计数与退役显存页(重要故障信号)

22.1.2 --query-gpu:自定义字段输出(运维核心技能)

默认输出是给"人"看的,而 --query-gpu 是给"脚本"看的——它让你精确指定要哪些字段、以什么格式输出。

bash
# 基本语法
nvidia-smi --query-gpu=<字段1,字段2,...> --format=csv

# 示例:查询最常用的 5 个字段
nvidia-smi --query-gpu=index,name,utilization.gpu,memory.used,memory.total,temperature.gpu,power.draw \
  --format=csv

输出示例:

csv
index, name, utilization.gpu [%], memory.used [MiB], memory.total [MiB], temperature.gpu, power.draw [W]
0, NVIDIA A100-SXM4-80GB, 87 %, 62140 MiB, 81920 MiB, 61, 385.22 W

常用查询字段对照表:

字段含义运维用途
index / uuidGPU 序号 / 唯一标识定位具体卡,uuid 跨重启不变
namedriver_version型号、驱动版本资产清点、版本一致性检查
utilization.gpuSM 利用率百分比(%)粗略判断忙闲(注意误区,见 22.2)
utilization.memory显存控制器利用率(%)判断显存带宽压力
memory.used / memory.total已用 / 总显存(MiB)显存占用监控
temperature.gpu / temperature.memory核心 / 显存温度(℃)过热告警(显存温度部分卡支持)
power.draw / power.limit当前功耗 / 功耗上限(W)功耗与降频分析
clocks.sm / clocks.max.smSM 当前 / 最大频率(MHz)判断是否降频
clocks_event_reasons.active降频原因(位掩码)排查为什么变慢
ecc.errors.corrected.volatile.total可纠正 ECC 错误总数健康巡检
ecc.errors.uncorrected.volatile.total不可纠正 ECC 错误总数严重告警信号
retired_pages.single_bit_ecc.count单比特错误退役页数显存老化评估
persistence_mode持久模式状态交付检查

完整字段列表见 nvidia-smi --help-query-gpu

22.1.3 循环采集脚本示例

巡检或临时观察训练任务时,常用循环采集脚本:

bash
#!/bin/bash
# gpu_watch.sh —— 每 2 秒采集一次 GPU 关键指标,写入 CSV 日志
LOG=${1:-gpu_metrics_$(date +%Y%m%d_%H%M%S).csv}
FIELDS="timestamp,index,utilization.gpu,utilization.memory,memory.used,temperature.gpu,power.draw,clocks.sm"

echo "采集日志写入: $LOG (Ctrl+C 停止)"
nvidia-smi --query-gpu=$FIELDS --format=csv,noheader,nounits -l 2 >> "$LOG"

-l 2 表示每 2 秒循环一次(只看实时画面直接 nvidia-smi -l 1)。配合 nounits(去掉单位)和 noheader(去掉表头),得到的 CSV 可以直接用 pandas 或 Excel 画图分析"训练过程中利用率是否周期性掉零"(常见于数据加载瓶颈)。

22.2 关键指标解读:看懂数字背后的真相

22.2.1 GPU 利用率的误区:100% ≠ 打满算力

utilization.gpu 的官方定义是:在过去采样周期内,GPU 上至少有一个 kernel 在执行的时间占比。这意味着哪怕一个 kernel 只用了 1 个 SM 中的 1 个线程,只要它在运行,这一秒就算"100% 利用率"。典型误区:某任务 util 显示 100%,profiler 却显示 SM 实际活跃占比只有 18%——kernel 大量时间在做显存拷贝、同步等待,或本身并行度很低。

运维启示

  • utilization.gpu 只能用来判断"卡上有没有活干",不能用来判断"活干得满不满"。
  • 评估真实算力消耗要用 profiling 指标(见 24.2 的 DCGM_FI_PROF_SM_ACTIVE)。
  • 利用率 100% 但训练慢,瓶颈通常在显存带宽、数据加载或通信,而不是"卡不够"。

22.2.2 显存占用

  • memory.used 接近 memory.total 不代表"快 OOM 了"——PyTorch/TensorFlow 默认会缓存几乎所有空闲显存(caching allocator)。判断真实需求应结合框架内的 torch.cuda.max_memory_allocated()
  • 显存长期占用但利用率为 0,通常是僵尸进程或忘记释放的任务,是回收资源的第一目标。

22.2.3 温度与功耗

指标健康参考(以 A100/H100 为例)
GPU 核心温度长期 < 75℃;> 85℃ 需警惕;接近 slowdown 阈值(约 90~95℃)会降频
显存温度(HBM)长期 < 90℃;> 95℃ 需检查风道/散热
功耗空闲约 60~100W;满载接近 TDP(A100 400W,H100 700W)

功耗异常低(如满载只有 150W/400W)往往说明降频或供电问题

22.2.4 时钟降频原因(clocks_event_reasons)

GPU 不会一直跑在最高频率。clocks_event_reasons.active 用位掩码告诉你"现在为什么没跑满频":

位标志含义处理建议
GpuIdle卡空闲自动降频省电正常
SwPowerCap软件功耗封顶触发降频功耗打到 power.limit,正常物理现象
HwThermalSlowdown(hw_slowdown)硬件过热降频危险:检查风扇、风道、机房温度
SwThermalSlowdown软件热降频(提前于硬件)同上,温度已接近阈值
SyncBoost多卡组同步 boost 限制一般正常

查询命令:

bash
nvidia-smi -q -d CLOCK | grep -A 10 "Clocks Event Reasons"
# 或查询式输出
nvidia-smi --query-gpu=index,clocks_event_reasons.active,\
clocks_event_reasons.sw_power_cap,clocks_event_reasons.hw_thermal_slowdown --format=csv

22.3 监控体系全景:三层指标模型

单机的 nvidia-smi 解决不了集群问题。一套完整的 GPU 监控体系分三层:

text
┌─────────────────────────────────────────────────────────┐
│ 第三层:业务指标(训练框架侧)                                │
│   loss 曲线、吞吐 samples/s、step 时间、MFU                │
│   采集方式:训练代码埋点 → Prometheus / TensorBoard / W&B   │
├─────────────────────────────────────────────────────────┤
│ 第二层:GPU 指标(本部分核心)                              │
│   利用率、显存、温度、功耗、XID、ECC、NVLink、PCIe 带宽      │
│   采集方式:dcgm-exporter(DaemonSet 部署,第 23 章)        │
├─────────────────────────────────────────────────────────┤
│ 第一层:节点指标                                            │
│   CPU、内存、磁盘 IO、网络(含 RDMA 网卡)、inode            │
│   采集方式:node-exporter(+ 可选 rdma-exporter)           │
└─────────────────────────────────────────────────────────┘

为什么要三层?看一个真实排查链路:训练吞吐下降 30% → 业务层(step 时间变长)→ GPU 层(利用率周期性归零)→ 节点层(磁盘 IO 打满,数据加载是瓶颈)。任何单一层的监控都无法完成这个定位。

三层指标统一汇入 Prometheus,由 Grafana 统一展示(第 24 章)。

22.4 无 GPU 环境学习提示

没有 GPU 也能学习本章和后续章节的大部分内容:

  1. 理解指标结构:dcgm-exporter 的指标格式是公开的,可直接阅读官方字段文档,把每个 DCGM_FI_* 字段和 nvidia-smi --query-gpu 的字段一一对应起来。
  2. 用假数据搭建演示链路:写一个脚本周期性生成伪造指标,用 node-exporter 的 textfile 收集器或迷你 exporter 暴露,接入 Grafana。面板、PromQL、告警规则的设计能力完全可以在假数据上练熟
  3. 读真实输出存档:找一份 nvidia-smi -q 真实输出(附录或网上),逐段对照 22.1 的表格精读。
  4. 云实例验证:花几元钱包一小时 T4 实例,把本章命令全部跑一遍,比看十遍文档有效。

本章小结

  • nvidia-smi -q 看全量,--query-gpu --format=csv 做脚本化采集,-l 循环观察。
  • utilization.gpu = 100% 不代表算力打满,只代表"有 kernel 在跑";真实算力要用 PROF 指标评估。
  • 降频原因看 clocks_event_reasons:功耗封顶多为正常,thermal 降频必须处理。
  • 完整监控 = 节点指标(node-exporter)+ GPU 指标(dcgm-exporter)+ 业务指标,三层缺一不可。
  • 无 GPU 环境可用模拟数据练习指标、面板与告警设计。

动手实验

  1. 执行 nvidia-smi --help-query-gpu,找出 5 个本教材未列出的字段,猜测含义并验证。
  2. 写一个采集脚本:每 5 秒记录所有 GPU 的 utilization.gpu,memory.used,temperature.gpu,power.draw 到 CSV,运行 10 分钟(期间跑一个 GPU 任务),画出 4 条曲线。
  3. 思考题:某卡 utilization.gpu=95% 但功耗只有上限的 40%,可能的原因有哪些?(提示:降频、kernel 类型、数据等待)
  4. (无 GPU 环境)编写 bash 脚本生成模拟 CSV 指标文件,字段同实验 2,数值随机但合理(温度 30~85℃)。

第 23 章 DCGM 与 dcgm-exporter

本章目标

  • 理解 DCGM 的架构(nv-hostengine、dcgmi)及其与 NVML 的关系
  • 掌握 dcgmi 常用命令:发现、健康检查、三级诊断
  • 在 K8s 中以 DaemonSet 部署 dcgm-exporter,读懂默认指标
  • 定制采集字段,并通过 ServiceMonitor 接入 Prometheus
  • 理解容器/Pod 级 GPU 指标的归属问题与 MIG 场景的指标特点

23.1 DCGM 架构:是什么、为什么需要它

NVML(NVIDIA Management Library)是驱动自带的底层 C 库——nvidia-smi 就是基于它做的。但它只面向单机。

DCGM(Data Center GPU Manager)是 NVIDIA 面向数据中心的 GPU 管理套件,在 NVML 之上提供了:

  • 后台服务 nv-hostengine:持续采集、缓存指标,支持多客户端共享查询
  • 命令行工具 dcgmi:分组管理多台机器/多张卡、健康检查、在线诊断
  • 导出器 dcgm-exporter:把指标转成 Prometheus 格式(K8s 监控的事实标准组件)
  • 健康与诊断框架:标准化的 GPU 体检(这是 nvidia-smi 做不到的)
text
 应用层    dcgm-exporter      dcgmi (CLI)        第三方工具
            │                   │
            └────── DCGM API(C/Python 绑定)──────

                    nv-hostengine(后台采集服务)

                     NVML(驱动用户态库)

                   NVIDIA 内核驱动 → GPU 硬件

使用 dcgm-exporter 时,nv-hostengine 会自动以内嵌模式启动,通常不需要手动管理服务dcgmi 命令行则需要连接 hostengine(dcgmi discovery 等命令默认连本机)。

23.2 dcgmi 常用命令

DCGM 用 group(组) 组织被管理的 GPU。默认有一个包含本机所有卡的组。

bash
dcgmi discovery -l          # 发现:列出本机所有 GPU 及状态
dcgmi group -l              # 查看组列表(默认组 ID 以实际输出为准)
dcgmi group -c mygroup      # 创建组;dcgmi group -g <组ID> -a 0,1 加卡

健康检查(生产高频命令)

bash
dcgmi health -g 0 -s a    # 开启全部健康检查项(p=PCIe m=显存ECC t=散热 n=NVLink)
dcgmi health -g 0 -a      # 查看健康状态:报告 PCIe、ECC、散热、电源等问题

三级诊断(dcgmi diag)——GPU 的"体检套餐"

级别命令内容耗时适用场景
Level 1dcgmi diag -r 1快速检查:驱动、ECC、PCIe、基本功能数秒~1 分钟日常巡检、交付前初检
Level 2dcgmi diag -r 2中等:显存测试、短时压力测试数分钟故障后验证、周检
Level 3dcgmi diag -r 3深度:长时间压力测试、NVLink、显存全面测试数十分钟新机器交付验收、疑难故障
bash
dcgmi diag -g 0 -r 1 -j    # 整组 Level 1,JSON 输出便于脚本处理
dcgmi diag -r 3 -i 2       # 只诊断 2 号卡的 Level 3

注意:Level 2/3 诊断会独占 GPU 并产生高负载,只能在排空业务后执行。

统计信息

bash
dcgmi stats -g 0 -e    # 开启对组的指标统计
dcgmi stats -g 0 -v    # 查看进程级 GPU 使用统计

23.3 dcgm-exporter 部署与默认指标

23.3.1 K8s DaemonSet 部署

dcgm-exporter 以 DaemonSet 跑在每个 GPU 节点上,暴露 :9400/metrics

yaml
apiVersion: apps/v1
kind: DaemonSet
metadata: {name: dcgm-exporter, namespace: monitoring}
spec:
  selector:
    matchLabels: {app: dcgm-exporter}
  template:
    metadata:
      labels: {app: dcgm-exporter}
    spec:
      nodeSelector:
        nvidia.com/gpu.present: "true"        # 只调度到有 GPU 的节点
      tolerations:
        - {key: nvidia.com/gpu, operator: Exists, effect: NoSchedule}
      containers:
        - name: dcgm-exporter
          image: nvcr.io/nvidia/k8s/dcgm-exporter:3.3.9-3.6.1-ubuntu22.04
          ports: [{name: metrics, containerPort: 9400}]
          securityContext:
            runAsNonRoot: false               # DCGM 需要访问驱动设备

实际生产中更常用 GPU Operator 一键部署(dcgmExporter.enabled=true),它自动处理镜像版本、节点选择器与 ServiceMonitor。手动部署适合学习原理。

验证:kubectl -n monitoring get pods -l app=dcgm-exporter -o wide,然后 curl -s http://<节点IP>:9400/metrics | grep DCGM_FI_DEV_GPU_UTIL

23.3.2 默认指标对照表(背熟这张表)

Prometheus 指标含义对应 nvidia-smi 字段
DCGM_FI_DEV_GPU_UTILSM 利用率(%)utilization.gpu
DCGM_FI_DEV_MEM_COPY_UTIL显存控制器利用率(%)utilization.memory
DCGM_FI_DEV_FB_USED / DCGM_FI_DEV_FB_FREE已用 / 空闲显存(MiB)memory.used / memory.free
DCGM_FI_DEV_GPU_TEMPGPU 核心温度(℃)temperature.gpu
DCGM_FI_DEV_MEMORY_TEMP显存温度(℃)temperature.memory
DCGM_FI_DEV_POWER_USAGE当前功耗(W)power.draw
DCGM_FI_DEV_SM_CLOCK / DCGM_FI_DEV_MEM_CLOCKSM / 显存时钟(MHz)clocks.sm / clocks.mem
DCGM_FI_DEV_XID_ERRORS最近一次 XID 错误码见第七部分,告警核心
DCGM_FI_DEV_ECC_SBE/DBE_VOL_TOTAL单/双比特 ECC 错误累计ecc.errors.corrected/uncorrected.volatile.total
DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTALNVLink 总带宽计数NVLink 状态
DCGM_FI_DEV_PCIE_TX/RX_THROUGHPUTPCIe 收发吞吐PCIe 带宽

每个指标都带标签:gpu(卡序号)、UUIDdevicemodelNameHostname(K8s 部署时还有 podnamespacecontainer),这是后续做面板和告警分组的基础。

23.4 自定义采集指标

dcgm-exporter 通过一个 CSV 配置文件定义采集哪些字段,格式为 字段ID, 采集频率

csv
# /etc/dcgm-exporter/custom.csv —— 自定义采集字段
# 格式: DCGM 字段名, 采集间隔(ms),1000 已足够,过密会增加 GPU 负载
DCGM_FI_DEV_GPU_UTIL,              1000
DCGM_FI_DEV_MEM_COPY_UTIL,         1000
DCGM_FI_DEV_FB_USED,               1000
DCGM_FI_DEV_GPU_TEMP,              1000
DCGM_FI_DEV_POWER_USAGE,           1000
DCGM_FI_DEV_XID_ERRORS,            1000
# 追加:profiling 指标(真实算力消耗,见 24.2)
DCGM_FI_PROF_SM_ACTIVE,            1000
DCGM_FI_PROF_SM_OCCUPANCY,         1000
DCGM_FI_PROF_PIPE_TENSOR_ACTIVE,   1000
DCGM_FI_PROF_DRAM_ACTIVE,          1000

挂载配置并启用:

yaml
          args: ["-f", "/etc/dcgm-exporter/custom.csv"]
          volumeMounts:
            - name: custom-csv
              mountPath: /etc/dcgm-exporter
      volumes:
        - name: custom-csv
          configMap:
            name: dcgm-custom-metrics

PROF 系列指标需要 DCGM 较新版本,且采集它们本质上是借用 GPU 的硬件性能计数器,与 CUPTI/nsight 等 profiler 同时运行可能冲突

23.5 与 Prometheus 集成

方式一:ServiceMonitor(Prometheus Operator 环境)

先给 DaemonSet 配一个 Service:

yaml
apiVersion: v1
kind: Service
metadata:
  name: dcgm-exporter
  namespace: monitoring
  labels: {app: dcgm-exporter}        # ServiceMonitor 按此 label 选择
spec:
  selector: {app: dcgm-exporter}
  ports: [{name: metrics, port: 9400, targetPort: 9400}]
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: dcgm-exporter
  namespace: monitoring
  labels: {release: prometheus}       # 与 Prometheus 的 serviceMonitorSelector 匹配
spec:
  selector:
    matchLabels: {app: dcgm-exporter}
  endpoints:
    - {port: metrics, interval: 15s, path: /metrics}

方式二:PodMonitor 或静态配置

无 Service 时可用 PodMonitor 直接抓 Pod(结构与 ServiceMonitor 类似,podMetricsEndpoints 指定 port: metrics);非 Operator 的原生 Prometheus 则用 kubernetes_sd_configs: role: pod 加 relabel 规则(按 __meta_kubernetes_pod_label_app=dcgm-exporter 保留目标)。二选一即可,中小集群用 ServiceMonitor 最直观。

23.6 容器/Pod 级 GPU 指标归属

这是生产中最容易踩的坑:GPU 是物理设备,指标天然是"卡"维度的,而业务是"Pod"维度的

归属是怎么建立的

dcgm-exporter 通过读取驱动维护的"进程 → GPU"映射并关联容器 cgroup 信息,给指标打上 podnamespacecontainer 标签。前提:exporter 容器能看到宿主的 cgroup/设备信息(GPU Operator 已自动处理);Pod 通过 nvidia.com/gpu 资源申请 GPU(device plugin 分配),而不是手动挂载 /dev/nvidia*。若标签缺失(如业务容器用 CUDA_VISIBLE_DEVICES 自行组合卡),指标只能精确到卡,归属要靠 24.6 的巡检脚本在节点侧人工补齐。

MIG 与共享场景的指标特点

场景指标行为
整卡独占正常,标签齐全
MIG 实例每个 MIG 实例是独立"GPU",指标带 GPU_I_ID / GPU_I_PROFILE 标签;MIG 实例没有独立的温度/功耗(共享物理卡),这些指标只在物理卡级别有效
时间片共享 / MPS多个 Pod 共用一张卡,DCGM_FI_DEV_GPU_UTIL整卡合计,无法区分每个 Pod 各用了多少;显存可看到各进程用量
HAMi 等显存切分框架内限制对 DCGM 不可见,DCGM 看到的仍是物理显存

运维启示:共享场景下"这张卡忙"≠"某个 Pod 忙",归属分析要结合调度信息(谁被调度到了这台节点这张卡)。

本章小结

  • DCGM = nv-hostengine(采集服务)+ dcgmi(CLI)+ dcgm-exporter(Prometheus 导出),构建在 NVML 之上。
  • dcgmi health -g 0 -a 做健康检查,dcgmi diag -r 1/2/3 做三级诊断(2/3 级必须排空业务)。
  • dcgm-exporter 以 DaemonSet 部署,默认指标覆盖利用率、显存、温度、功耗、XID、ECC;CSV 定制字段,PROF 指标需显式开启。
  • 用 ServiceMonitor/PodMonitor 接入 Prometheus Operator。
  • Pod 级归属依赖 device plugin 分配方式;MIG 无独立温度功耗,共享场景利用率是整卡合计。

动手实验

  1. 安装 DCGM,执行 dcgmi discovery -ldcgmi diag -r 1,记录输出。
  2. 部署 dcgm-exporter(Docker 或 K8s 均可),curl :9400/metrics,找出本章指标表中的每个指标。
  3. 修改 CSV 只保留 5 个字段,重启 exporter,验证指标数量变化。
  4. 思考题:为什么 DCGM_FI_DEV_XID_ERRORS 只表示"最近一次 XID 码"而非累计计数?对告警设计有何影响?(提示:24.3 用 > 0 触发)

第 24 章 Grafana 可视化与告警体系

本章目标

  • 基于社区 Dashboard 快速搭建集群级可视化,并设计核心面板
  • 理解利用率平均值高估问题,学会用 PROF 指标评估真实算力
  • 编写覆盖掉卡、XID、温度、显存、低利用率的 PrometheusRule 告警,并用 Alertmanager 分级路由
  • 知道 GPU 相关日志在哪里,了解用 Loki 收集 XID 日志的思路
  • 完成一个端到端的"集群 GPU 健康总览"巡检脚本

24.1 Grafana Dashboard 搭建

24.1.1 导入社区 Dashboard(5 分钟见效)

NVIDIA 官方和社区维护了现成的 DCGM Dashboard:

  1. Grafana → Dashboards → Import
  2. 输入社区 ID(常用的是 12239,NVIDIA DCGM Exporter Dashboard;以 grafana.com 搜索结果为准)
  3. 选择 Prometheus 数据源,确认导入

导入后先验证数据:没有曲线时按"Prometheus targets 是否 UP → exporter 是否出指标 → 时间范围"顺序排查。

24.1.2 集群级总览面板设计

社区面板偏"单机多卡",生产还需要一个集群运营视角的总览面板,建议包含:

面板PromQL 示例说明
集群 GPU 总数count(DCGM_FI_DEV_GPU_UTIL)有多少张卡被监控到
健康卡数count(DCGM_FI_DEV_XID_ERRORS == 0)近似健康度(掉卡时总数会减少,见 24.3)
集群平均利用率avg(DCGM_FI_DEV_GPU_UTIL)宏观忙闲(注意 24.2 的误区)
集群显存占用比sum(DCGM_FI_DEV_FB_USED) / sum(DCGM_FI_DEV_FB_USED + DCGM_FI_DEV_FB_FREE)显存维度压力
温度 TopN 节点topk(5, avg by (Hostname) (DCGM_FI_DEV_GPU_TEMP))找出散热隐患节点
XID 事件changes(DCGM_FI_DEV_XID_ERRORS[15m]) > 0最近 XID 变动
利用率分布直方图bar gauge 分档统计一眼看出"多少卡闲着"

24.2 利用率计算误区:为什么平均值会高估

  • 问题 1:时间平均高估。 util 表示"采样窗口内有 kernel 在跑的时间占比",一个每 100ms 只跑 5ms kernel 的任务可能显示接近 100%,真实算力消耗只有 5%。
  • 问题 2:空间平均掩盖闲置。 avg() 把 8 张卡平均后,"7 张满载 + 1 张空闲"显示 87.5%,但那 1 张空闲卡可能正卡着分布式训练的全部进度(木桶效应)。

解决方案:PROF(profiling)指标。 DCGM 可以读取 GPU 硬件性能计数器:

指标含义
DCGM_FI_PROF_SM_ACTIVESM 至少有一个 warp 活跃的时间占比(真实算力消耗的核心指标
DCGM_FI_PROF_SM_OCCUPANCYSM 上 warp 占用率(并行度是否吃满)
DCGM_FI_PROF_PIPE_TENSOR_ACTIVETensor Core 管道活跃占比(AI 负载关键)
DCGM_FI_PROF_DRAM_ACTIVE显存带宽利用率

解读组合示例:GPU_UTIL=100% + SM_ACTIVE=95% → 真满载;GPU_UTIL=100% + SM_ACTIVE=20% + DRAM_ACTIVE=80%显存带宽瓶颈GPU_UTIL=100% + SM_ACTIVE=20% + DRAM_ACTIVE=10% → kernel 并行度低或频繁同步,代码问题

启用方式:DCGM 2.4+ 在 dcgm-exporter 的 CSV 配置中加入 DCGM_FI_PROF_* 字段(见 23.4),部分部署形态提供 --enable-profiling 类开关。注意 PROF 指标与同节点的 CUPTI profiler(nsys/ncu)互斥。

24.3 告警规则设计(PrometheusRule)

yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata: {name: gpu-cluster-alerts, namespace: monitoring}
spec:
  groups:
    - name: gpu-hardware
      rules:
        # P0:掉卡——节点上报的 GPU 数量比 10 分钟前减少
        - alert: GPUCardLost
          expr: |
            count by (Hostname) (DCGM_FI_DEV_GPU_UTIL)
              < on(Hostname) count by (Hostname) (DCGM_FI_DEV_GPU_UTIL offset 10m)
          for: 2m
          labels: {severity: P0}
          annotations:
            summary: "节点 {{ $labels.Hostname }} 掉卡"
            description: "10 分钟内 GPU 数量减少,常见 XID 79/48,需立即排查并考虑下线节点。"

        # P0:XID 错误(出现即告警,XID 语义见第七部分)
        - alert: GPUXIDError
          expr: DCGM_FI_DEV_XID_ERRORS > 0
          labels: {severity: P0}
          annotations:
            summary: "{{ $labels.Hostname }} GPU {{ $labels.gpu }} 出现 XID {{ $value }}"
            description: "79=掉总线、48=双比特ECC、63/64=显存故障,通常需隔离维修。"

        # P1:不可纠正 ECC 错误增长 / 温度过高
        - alert: GPUECCDBEGrowing
          expr: increase(DCGM_FI_DEV_ECC_DBE_VOL_TOTAL[30m]) > 0
          labels: {severity: P1}
          annotations:
            summary: "{{ $labels.Hostname }} GPU {{ $labels.gpu }} 双比特 ECC 错误增长"
        - alert: GPUTemperatureHigh
          expr: DCGM_FI_DEV_GPU_TEMP > 85
          for: 5m
          labels: {severity: P1}
          annotations:
            summary: "{{ $labels.Hostname }} GPU {{ $labels.gpu }} 温度 {{ $value }}℃"

        # P2:显存占用长期 >95%(OOM 风险)
        - alert: GPUMemoryPressure
          expr: DCGM_FI_DEV_FB_USED / (DCGM_FI_DEV_FB_USED + DCGM_FI_DEV_FB_FREE) > 0.95
          for: 30m
          labels: {severity: P2}
          annotations:
            summary: "{{ $labels.Hostname }} GPU {{ $labels.gpu }} 显存占用长期超 95%"

        # P3:占着显存但利用率长期 <10% —— 资源浪费
        - alert: GPUIdleWaste
          expr: |
            avg_over_time(DCGM_FI_DEV_GPU_UTIL[6h]) < 10
              and on(Hostname, gpu) DCGM_FI_DEV_FB_USED > 1000
          for: 1h
          labels: {severity: P3}
          annotations:
            summary: "{{ $labels.Hostname }} GPU {{ $labels.gpu }} 占显存但 6h 平均利用率 <10%"

设计要点:

  • 掉卡用"卡数对比"而非 exporter down:两者是两回事,应另配 up == 0 采集告警。
  • XID 用 > 0 瞬时触发:该指标表示最近一次错误码,为 0 才是无错误。
  • 低利用率要加显存条件:完全空闲是"未分配",占着显存不用才是"浪费"。
  • 阈值按自家卡型(T4/A100/H100 不同)和业务特点调整。

24.4 告警分级与通知(Alertmanager)

yaml
# alertmanager.yaml 片段
route:
  receiver: default-im
  group_by: [alertname, Hostname]
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  routes:
    - matchers: [severity = "P0"]        # 掉卡/XID —— 电话 + IM
      receiver: p0-phone-and-im
      repeat_interval: 30m
    - matchers: [severity = "P1"]        # 硬件风险 —— IM @值班
      receiver: p1-im-oncall
    - matchers: [severity =~ "P2|P3"]    # 优化类 —— 进周报队列
      receiver: weekly-report-queue

receivers:
  - name: p0-phone-and-im
    webhook_configs: [{url: http://phone-gateway/alert}]   # 电话通知网关
  - name: p1-im-oncall
    webhook_configs: [{url: http://im-bot/oncall}]         # 企业微信/飞书 @值班人
  - name: weekly-report-queue
    webhook_configs: [{url: http://report-collector/gpu}]  # 收集后每周汇总
  - name: default-im
    webhook_configs: [{url: http://im-bot/general}]

分级哲学:P0(掉卡、XID 79/48,业务正在受损,分钟级响应,电话);P1(温度异常、ECC 增长,硬件风险信号,小时级响应,IM @值班);P2(显存压力等,天级处理,工单/日报);P3(低利用率浪费,资源优化议题,进周报,绝不打扰值班人)。

24.5 日志体系补充:指标之外的关键信息

指标告诉你"卡出问题了",日志告诉你"为什么"。GPU 相关日志位置:

日志来源位置内容
内核日志dmesg / journalctl -kXID 错误的权威出处NVRM: Xid ...)、驱动加载、掉卡
系统日志/var/log/syslog驱动相关用户态事件
kubeletjournalctl -u kubeletPod 分配 GPU 失败、device plugin 注册异常
device pluginkubectl -n kube-system logs <nvidia-device-plugin-pod>卡发现、健康上报、分配记录
fabric managerjournalctl -u nvidia-fabricmanagerNVSwitch 机型(DGX/HGX H100)NVLink fabric 状态
dcgm-exporterPod 日志采集异常

用 Loki 收集 XID 日志的示意(Promtail 管道规则):

yaml
# promtail 配置片段:从内核日志中识别 XID,打标签便于检索与告警
pipeline_stages:
  - match:
      selector: '{job="node-journal", unit="kernel"}'
      stages:
        - regex:
            expression: 'NVRM: Xid \(PCI:(?P<pci>[^)]+)\): (?P<xid>\d+),'
        - labels: {xid: "", pci: ""}

之后在 Grafana 用 LogQL 检索 {job="node-journal"} |= "NVRM: Xid",并可配置"高危 XID → 告警"的日志告警规则,与 24.3 的指标告警互补(日志通常比指标更早出现细节)。

24.6 完整实战:集群 GPU 健康总览巡检脚本

即使有了全套监控,运维仍需要一份"一键跑完、一眼看完"的巡检脚本——用于交班、交付验收、故障初判。以下脚本在每个 GPU 节点执行(或用 pssh/ansible 批量下发):

bash
#!/bin/bash
# gpu_health_report.sh —— 集群 GPU 健康总览巡检(单节点版)
# 用法: bash gpu_health_report.sh  (需要 nvidia-smi;dcgmi 可选)

echo "================ GPU 健康巡检报告: $(hostname)  $(date) ================"

# 1. 卡数与型号
echo -e "\n[1] GPU 清单"
nvidia-smi --query-gpu=index,name,driver_version,persistence_mode \
  --format=csv,noheader | column -t -s ','

# 2. 核心指标表:利用率/显存/温度/功耗/时钟
echo -e "\n[2] 核心指标 (util% | mem_used/total MiB | temp℃ | power W | sm_clock MHz)"
nvidia-smi --query-gpu=index,utilization.gpu,memory.used,memory.total,\
temperature.gpu,power.draw,clocks.sm \
  --format=csv,noheader,nounits | \
  awk -F',' '{printf "GPU%-2s util:%4s%%  mem:%7s/%-7s  temp:%3s℃  power:%6sW  clk:%5sMHz\n",\
    $1,$2,$3,$4,$5,$6,$7}'

# 3. 降频原因检查(列出非 Idle 的激活原因)
echo -e "\n[3] 降频原因 (非 Idle 项)"
nvidia-smi --query-gpu=index,clocks_event_reasons.sw_power_cap,\
clocks_event_reasons.sw_thermal_slowdown,clocks_event_reasons.hw_thermal_slowdown \
  --format=csv,noheader,nounits | \
  awk -F',' '{if($2!~/(^0|Not)/ || $3!~/(^0|Not)/ || $4!~/(^0|Not)/)
    print "GPU"$1" 降频激活: sw_power_cap="$2" sw_thermal="$3" hw_thermal="$4}'

# 4. ECC 与退役页(DBE 或双比特退役页 >0 时标记"关注")
echo -e "\n[4] ECC 错误 / 退役页"
nvidia-smi --query-gpu=index,ecc.errors.corrected.volatile.total,\
ecc.errors.uncorrected.volatile.total,retired_pages.double_bit_ecc.count \
  --format=csv,noheader,nounits | \
  awk -F',' '{flag=($3>0 || $4>0)?"  <== 关注":"";
    printf "GPU%-2s SBE:%-6s DBE:%-4s retired_dbe:%-4s%s\n",$1,$2,$3,$4,flag}'

# 5. 最近 XID(内核日志)
echo -e "\n[5] 最近 10 条 XID 日志"
{ dmesg -T 2>/dev/null; journalctl -k --no-pager 2>/dev/null; } | \
  grep -i "NVRM: Xid" | tail -n 10 || echo "(无权限或无 XID 记录)"

# 6. GPU 上的进程
echo -e "\n[6] 占卡进程"
nvidia-smi --query-compute-apps=gpu_uuid,pid,process_name,used_memory \
  --format=csv,noheader || echo "无计算进程"

# 7. DCGM Level 1 快速诊断(如安装了 dcgmi)
if command -v dcgmi >/dev/null 2>&1; then
  echo -e "\n[7] DCGM Level 1 快速诊断"
  dcgmi diag -r 1 2>/dev/null | grep -E "Result|Overall|Fail" || echo "诊断执行失败"
fi
echo -e "\n================ 巡检完成 ================"

输出节选示例:

text
[2] 核心指标
GPU0  util:  87%  mem:  62140/81920    temp: 61℃  power:385.2W  clk: 1410MHz
[4] ECC 错误 / 退役页
GPU1  SBE:0     DBE:2    retired_sbe:0    retired_dbe:3  <== 关注

批量执行:pssh -h gpu_nodes.txt -i 'bash -s' < gpu_health_report.sh,输出汇总到跳板机归档,配合周报使用。

本章小结

  • 先导入社区 DCGM Dashboard 快速见效,再按集群运营视角自建总览面板(卡数/健康/利用率/温度 TopN)。
  • GPU_UTIL 平均值会高估真实算力,用 DCGM_FI_PROF_SM_ACTIVE 等 PROF 指标还原真相,组合可区分算力/带宽/代码瓶颈。
  • 告警五件套:掉卡(卡数对比)、XID(>0 瞬时)、温度、显存压力、低利用率浪费;按 P0~P3 分级路由,优化类进周报。
  • XID 的权威信息在内核日志,用 Loki/Promtail 收集并打标。
  • 巡检脚本是监控体系的补充:交班、验收、故障初判一键完成。

动手实验

  1. 导入社区 DCGM Dashboard,指出 3 个面板对应的 PromQL,解释每个函数的作用。
  2. 新建"集群总览"Dashboard,实现 24.1.2 表格中至少 4 个面板。
  3. 应用 24.3 的 PrometheusRule,手工构造条件(模拟指标或压力工具)触发任意两条告警。
  4. 配置 Alertmanager,把 P3 级告警路由到独立 webhook,验证分组与静默逻辑。
  5. 运行 24.6 巡检脚本并归档输出;找出输出中每一项与 DCGM 指标的对应关系。
  6. 思考题:"集群平均利用率 60%"为何不能直接用于汇报资源使用情况?应补充哪些维度?(提示:分布、PROF 指标、排队任务数)

下一部分预告:第七部分 GPU 故障诊断与运维实战——把本部分学到的监控告警能力用在刀刃上,系统处理 XID 错误、掉卡、ECC 故障、NVLink 异常等真实生产故障。