学习库/ AI Infra 转型/ 11 · 11 GPU 可观测与性能调优
🧠 AI Infra 转型 · 第 12 / 17 篇

11 GPU 可观测与性能调优

2981 字· 阅读约 7 分钟· 2026-08-23 更新

11 GPU 可观测与性能调优

阶段三后半段。前面你会「把模型跑起来」,这一章学怎么看见 GPU 在干嘛、怎么判断它健不健康、利用率低时从哪几个维度排查。这是 AI Infra 工程师的「运维之眼」,也是面试能讲出「我优化过」的关键。

💡 给你的话:这章是你的 SRE 老本行——Prometheus/Grafana 你熟,只是指标换成 GPU 的。核心是学会「利用率低≠要加卡,先找根因」。


11.1 为什么可观测是 AI Infra 的命门

  • GPU 极贵,利用率从 30%→70% 等于凭空多出一倍算力(呼应 03/05 的 TCO 杠杆)。
  • 但「利用率低」只是表象,根因可能是:显存瓶颈、通信瓶颈、数据瓶颈、算子慢、拓扑错。看不见就无从优化。
  • 可观测 = 指标(metrics)+ 日志(logs)+ 链路追踪(traces)+ 剖析(profiling) 四件套。

名词解释

  • 指标(Metrics):可聚合的数值时序数据(如利用率、温度)。
  • 剖析(Profiling):对程序运行做细粒度采样分析,定位哪个函数/算子耗时。

11.2 指标体系:DCGM-Exporter

DCGM(Data Center GPU Manager) 是 NVIDIA 的 GPU 遥测库;DCGM-Exporter 把它暴露成 Prometheus 可抓取的指标(呼应 04 GPU Operator 里的组件)。

指标(示例) 含义 排查用途
DCGM_FI_DEV_GPU_UTIL GPU 计算利用率 % 整体忙不忙
DCGM_FI_DEV_MEM_COPY_UTIL 显存带宽利用率 % 是否「等数据」
DCGM_FI_DEV_FB_USED 显存已用 是否快溢出
DCGM_FI_DEV_POWER / TEMP 功耗 / 温度 降频/散热
DCGM_FI_PROF_PIPE_* Tensor/FP 活跃度 算力用满没
DCGM_FI_PROF_NVLINK_* NVLink 流量 卡间通信是否打满

⭐ 看 GPU 不能只看 nvidia-smi 的利用率——那个数字是「过去 1s 有无 kernel 在跑」的粗略值。DCGM 的 SM 占用率、显存带宽利用率才更接近真相。

名词解释kernel:在 GPU 上执行的一个并行函数(一个算子对应一个或多个 kernel)。nvidia-smi:NVIDIA 的命令行 GPU 状态查看工具。


11.3 Prometheus + Grafana 采集展示

链路:DCGM-Exporter(Pod)→ Prometheus(抓指标)→ Grafana(看板)

# DCGM-Exporter 由 GPU Operator 自动部署;Prometheus 抓取示例
scrape_configs:
  - job_name: dcgm
    static_configs:
      - targets: ['dcgm-exporter:9400']

常用 Grafana 看板:NVIDIA 官方 DCGM-Exporter dashboard,可直接导入。配合 K8s 层的 kube-state-metricscadvisor,能同时看「节点 GPU 指标 + Pod 调度关系」。

名词解释cadvisor:Google 的容器资源监控工具;kube-state-metrics:暴露 K8s 对象状态指标的组件。你应该都熟。


11.4 ⭐ GPU 利用率低的分维度排查法

看到 GPU_UTIL 低,按下面顺序排查(从最常见到最隐蔽):

  1. 数据瓶颈(最常见):DataLoader 慢、存储 IO 跟不上 → GPU 在等数据。看 CPU/磁盘 IO、加大 num_workers、用更快存储(见 12.9)。
    • 名词解释DataLoader:PyTorch 加载数据的组件;num_workers 是并行加载进程数。
  2. 显存/计算搬运瓶颈MEM_COPY_UTIL 高但 GPU_UTIL 不高 → 在「等数据搬运」。优化:算子融合、FlashAttention、用更大 batch。
  3. 通信瓶颈(多机):训练扩展差 → NCCL/IB 没跑满或走了以太网。看 NVLINK_*、IB 端口统计、NCCL 日志(见 09.6)。
  4. 算子慢:个别 kernel 效率低 → 用 Nsight/Profiler 定位(见 11.6)。
  5. 拓扑错:任务被打散到跨节点高延迟位置 → 调度没做 NVLink/NUMA 亲和(见 06/07)。
  6. batch 太小 / 没批处理:推理没开连续批处理 → 见 10.2

⭐ 一句话:先分「等数据/等通信/算得慢」三类,再对症优化。这是面试最能讲出业务价值的能力。

⚠️ 内幕:实际排查 80% 的情况是前两类(数据瓶颈或搬运瓶颈)。新手常误以为「利用率低 = 要加卡」,实际多半是 DataLoader/存储/通信拖后腿,加卡也白加。先排查再扩容,是 AI Infra 工程师的专业素养。


11.5 CUDA 基础与算子优化

CUDA 执行模型(够用即可)

  • GPU 把计算组织成 Grid → Block → Thread 层次;一个 kernel 在大量 thread 上并行。
    • 名词解释Grid / Block / Thread:CUDA 的执行层级。一个 kernel 启动一个 Grid,Grid 含多个 Block,Block 含多个 Thread。类比:Grid=整支军队,Block=连,Thread=士兵。
  • SM(Streaming Multiprocessor) 是执行单元;occupancy(占用率) 高 ≠ 快,要看是否真在算有效工作。

算子融合(Operator Fusion)

  • 多个小算子(如 LayerNorm+激活+MatMul)合成一个 kernel,减少显存读写往返——呼应 01.6「瓶颈在搬运」。
    • 名词解释LayerNorm(层归一化):神经网络里把一层输出做标准化的操作;激活函数(Activation):给网络加非线性,如 ReLU。
  • 框架(PyTorch 2.0 torch.compile、XLA)会自动融合;手写 CUDA/Triton 可进一步定制。
    • 名词解释torch.compile:PyTorch 2.0 的 JIT 编译,自动优化图。XLA:Google 的编译器,把计算图编译优化。Triton(OpenAI):比 CUDA 易写的 GPU 编程语言。

FlashAttention

  • 对注意力计算做 IO 感知的精确重写,不 materialize 巨大的中间矩阵,显存随序列长度线性而非平方增长,且更快。
    • 名词解释materialize:把中间结果实际写到显存。FlashAttention 通过分块计算避免写巨大中间矩阵。
  • 已成为训练/推理默认组件(vLLM/SGLang 都依赖类 FlashAttention 内核)。

11.6 性能剖析工具

工具 用途
Nsight Systems 时间线剖析:CPU/GPU/NCCL 活动、kernel 耗时、缝隙(bubble)
Nsight Compute 单 kernel 深度剖析:occupancy、带宽、瓶颈指令
torch.profiler PyTorch 层算子级耗时,导出 Chrome trace
py-spy 无侵入看 Python 栈,定位 DataLoader/预处理卡点
DCGM 前述实时指标

实战套路:先用 py-spy 看是不是 Python/数据卡住 → 用 torch.profiler 看算子耗时 → 用 Nsight Systems 看 GPU 时间线和通信缝隙。

💡 类比:py-spy 像「看哪个线程卡住」(你熟悉的 pprof/strace 思路),Nsight Systems 像「看 GPU 时间线」(像火焰图但跨 CPU/GPU/通信)。


11.7 NCCL 调试速查

  • NCCL_DEBUG=INFO 看通信初始化与路径选择。
  • NCCL_IB_DISABLE=1 强制走以太网(排查 IB 问题时用);正常应让 NCCL 用 IB。
  • NCCL_TOPO_FILE 指定拓扑,优化多卡路径。
  • 多机训练慢,先确认 NCCL 是否选了 IB 而非以太网、是否跨节点打散。

⚠️ 内幕:多机训练「跑起来但很慢」第一嫌疑就是 NCCL 走了以太网而非 IB——配置错或 IB 网卡没识别。NCCL_DEBUG=INFO 日志里看通信路径选了什么,一目了然。


11.8 实战:装一套 GPU 监控

# GPU Operator 已含 DCGM-Exporter;确认 Pod 在跑
kubectl get pods -n gpu-operator | grep dcgm

# 本地快速验证指标端点
kubectl port-forward -n gpu-operator svc/dcgm-exporter 9400:9400
curl localhost:9400/metrics | grep DCGM_FI_DEV_GPU_UTIL

# 导入 Grafana 官方 DCGM dashboard(ID 12239 或 NVIDIA 提供)

11.9 实战:在 K8s 上搭建监控体系(Prometheus + Grafana)

没有 GPU 也能搭完整的监控链路——这一节在 kind 上安装 Prometheus + Grafana,采集节点指标,建看板。

11.9.1 安装 kube-prometheus-stack

# 复用 kind 集群(或新建一个)
kind create cluster --name monitor-lab

# 添加 Prometheus Helm 仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# 一键安装 Prometheus + Grafana + Alertmanager + node-exporter
helm install kube-prometheus prometheus-community/kube-prometheus-stack \
  -n monitoring --create-namespace

# 等待所有组件就绪(约 2-3 分钟)
kubectl get pods -n monitoring -w
# 应看到:
#   kube-prometheus-prometheus-node-exporter-xxx  Running
#   prometheus-kube-prometheus-prometheus-xxx     Running
#   kube-prometheus-grafana-xxx                    Running
#   alertmanager-kube-prometheus-alertmanager-xxx   Running

目的:kube-prometheus-stack 是 K8s 监控的「全家桶」——Prometheus 采集存储指标、Grafana 可视化、Alertmanager 告警、node-exporter 采集节点指标。真实 GPU 集群只需加 DCGM-Exporter 采集 GPU 指标。

11.9.2 访问 Grafana

# 获取 Grafana 初始密码
kubectl get secret -n monitoring kube-prometheus-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
# 默认用户名:admin

# 端口转发到本地
kubectl port-forward -n monitoring svc/kube-prometheus-grafana 3000:80 &

# 打开浏览器访问 http://localhost:3000
# 用 admin + 上面的密码登录

目的:Grafana 是可视化看板。kube-prometheus-stack 自带了「K8s 集群监控」看板,你能看到节点 CPU/内存/网络/磁盘的实时数据。真实 GPU 集群会多一组 DCGM GPU 看板。

11.9.3 查看节点指标

# 进入 Prometheus 查询界面
kubectl port-forward -n monitoring svc/kube-prometheus-prometheus 9090:9090 &
# 打开 http://localhost:9090

# 在查询框输入(模拟 GPU 指标查询):
# CPU 使用率:
  100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# 内存使用率:
  (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
# 磁盘 IO:
  rate(node_disk_io_time_seconds_total[5m])

目的:这模拟了 11.1 讲的「可观测是 AI Infra 的命门」——你在 Prometheus 查询里看到的就是 DCGM-Exporter 采集 GPU 指标的同样机制。真实 GPU 集群把 node_cpu_* 换成 DCGM_FI_DEV_GPU_UTIL 即可。

11.9.4 模拟 GPU 指标(fake DCGM-Exporter)

# 没有 GPU,我们模拟一些 GPU 指标,让 Prometheus 采集
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fake-dcgm-exporter
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: fake-dcgm
  template:
    metadata:
      labels:
        app: fake-dcgm
    spec:
      containers:
      - name: exporter
        image: prom/node-exporter:latest
        # 这里用 node-exporter 模拟 DCGM-Exporter
        # 真实环境换成 nvcr.io/nvidia/k8s/dcgm-exporter:3.3.0-ubuntu22.04
        ports:
        - containerPort: 9100
          name: metrics
EOF

# 创建 ServiceMonitor 让 Prometheus 采集
cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: fake-dcgm-monitor
  namespace: monitoring
  labels:
    release: kube-prometheus
spec:
  selector:
    matchLabels:
      app: fake-dcgm
  endpoints:
  - port: metrics
    interval: 15s
EOF

# 在 Prometheus 查询界面验证
# 访问 http://localhost:9090/targets,应看到 fake-dcgm 已被采集

目的:这模拟了 DCGM-Exporter 的工作方式——一个 Pod 暴露 /metrics 端点,Prometheus 通过 ServiceMonitor 定期采集。真实 GPU 把 node-exporter 换成 DCGM-Exporter,指标名从 node_* 变成 DCGM_FI_DEV_*

11.9.5 设置告警规则

# 创建一个 PrometheusRule(模拟「GPU 利用率低告警」)
cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: gpu-alerts
  namespace: monitoring
  labels:
    release: kube-prometheus
spec:
  groups:
  - name: gpu.rules
    rules:
    # 模拟「GPU 利用率低于 20% 持续 10 分钟」告警
    - alert: GpuUtilizationLow
      expr: avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) > 0.8
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: "节点 CPU/GPU 利用率低于 20%"
        description: "节点 {{ \$labels.instance }} 利用率过低,检查是否有任务卡住"
    # 模拟「GPU 温度过高」告警
    - alert: GpuTemperatureHigh
      expr: avg(node_hwmon_temp_celsius) > 80
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: "温度超过 80°C"
        description: "节点 {{ \$labels.instance }} 温度过高"
EOF

# 在 Grafana Alert 页面可以看到告警规则
# 或在 Prometheus http://localhost:9090/rules 查看

目的:这模拟了 11.8.1 讲的告警——真实 GPU 把 CPU 利用率阈值换成 DCGM_FI_DEV_GPU_UTIL < 20,温度换成 DCGM_FI_DEV_GPU_TEMP > 80

11.9.6 在 Grafana 建一个 GPU 监控看板

# 在 Grafana(http://localhost:3000)中:
# 1. 点 "+ Create Dashboard"
# 2. 添加以下 Panel:

Panel 1: GPU 利用率
  查询:avg(rate(node_cpu_seconds_total{mode!="idle"}[5m])) * 100
  Y 轴单位:percent

Panel 2: 内存使用率
  查询:(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
  Y 轴单位:percent

Panel 3: 磁盘 IO
  查询:rate(node_disk_io_time_seconds_total[5m])

Panel 4: 网络流量
  查询:rate(node_network_receive_bytes_total[5m])

目的:亲手建看板让你理解「可观测 = 指标采集 + 看板 + 告警」的完整链路。真实 GPU 看板只是指标名不同(DCGM_FI_DEV_GPU_UTIL 等),Grafana 配置完全一样。

11.9.7 清理

helm uninstall kube-prometheus -n monitoring
kubectl delete namespace monitoring --ignore-not-found
kind delete cluster --name monitor-lab

11.10 自测题

  1. 为什么只看 nvidia-smi 利用率会误判?DCGM 哪些指标更接近真相?
  2. Prometheus + Grafana + DCGM-Exporter 的采集链路是什么?
  3. ⭐ GPU 利用率低时,按什么顺序排查?列出至少 4 类根因。
  4. 算子融合和 FlashAttention 为什么能提速?本质解决了什么?什么是 materialize?
  5. Nsight Systems / torch.profiler / py-spy 各自看什么?用排查套路串起来。
  6. NCCL 调试为什么要看它走了 IB 还是以太网?NCCL_DEBUG=INFO 看什么?
  7. ⭐ 「利用率低 = 要加卡」这个判断为什么常错?

答上即完成阶段三(训练/推理/可观测)。下一步 12——把前面所有层组装成一个迷你 TI-ONE 平台。

← 返回专栏