11 GPU 可观测与性能调优
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-metrics、cadvisor,能同时看「节点 GPU 指标 + Pod 调度关系」。
名词解释:cadvisor:Google 的容器资源监控工具;kube-state-metrics:暴露 K8s 对象状态指标的组件。你应该都熟。
11.4 ⭐ GPU 利用率低的分维度排查法
看到 GPU_UTIL 低,按下面顺序排查(从最常见到最隐蔽):
- 数据瓶颈(最常见):DataLoader 慢、存储 IO 跟不上 → GPU 在等数据。看 CPU/磁盘 IO、加大
num_workers、用更快存储(见12.9)。- 名词解释:DataLoader:PyTorch 加载数据的组件;
num_workers是并行加载进程数。
- 名词解释:DataLoader:PyTorch 加载数据的组件;
- 显存/计算搬运瓶颈:
MEM_COPY_UTIL高但GPU_UTIL不高 → 在「等数据搬运」。优化:算子融合、FlashAttention、用更大 batch。 - 通信瓶颈(多机):训练扩展差 → NCCL/IB 没跑满或走了以太网。看
NVLINK_*、IB 端口统计、NCCL 日志(见09.6)。 - 算子慢:个别 kernel 效率低 → 用 Nsight/Profiler 定位(见
11.6)。 - 拓扑错:任务被打散到跨节点高延迟位置 → 调度没做 NVLink/NUMA 亲和(见
06/07)。 - 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 自测题
- 为什么只看
nvidia-smi利用率会误判?DCGM 哪些指标更接近真相? - Prometheus + Grafana + DCGM-Exporter 的采集链路是什么?
- ⭐ GPU 利用率低时,按什么顺序排查?列出至少 4 类根因。
- 算子融合和 FlashAttention 为什么能提速?本质解决了什么?什么是 materialize?
- Nsight Systems / torch.profiler / py-spy 各自看什么?用排查套路串起来。
- NCCL 调试为什么要看它走了 IB 还是以太网?
NCCL_DEBUG=INFO看什么? - ⭐ 「利用率低 = 要加卡」这个判断为什么常错?
答上即完成阶段三(训练/推理/可观测)。下一步
12——把前面所有层组装成一个迷你 TI-ONE 平台。