万卡级算力集群 GPU 监控:基于观测云全链路观测实践

本文介绍如何通过观测云监控万卡级算力集群 GPU,与应用性能 Trace、业务日志、基础设施指标在统一平台中实现全栈关联与跨层下钻,真正构建起从硬件到业务的完整观测链路。

最佳实践
1.png

背景

在大模型与生成式 AI 驱动的智能算力时代,万卡级 GPU 算力集群已成为企业数字化转型的核心战略基础设施——从千亿参数大模型的分布式训练,到高并发推理服务的实时响应,数万张 GPU 协同构筑的算力网络,正在重新定义技术创新的边界与商业竞争的格局。然而,随着集群规模从百卡迈向万卡级,GPU 资源的可观测性正面临前所未有的挑战:传统监控手段仅能触达设备层的温度与利用率,无法穿透到进程、容器、CUDA 内核等更深层级,更难以实现从基础设施到应用层的全链路关联分析。

然而,当前绝大多数 GPU 监控方案仍停留在"设备健康检查"的初级阶段——部署 DCGM Exporter,通过 Prometheus 抓取 9400 端口指标,在 Grafana 中搭建温度与利用率面板,设置 85°C 告警阈值,便宣告监控体系建成。这种"开箱即用"的方案在单机房、几十张卡的规模下尚可应付,但面对万卡级算力集群的复杂拓扑与多租户混合负载场景,其观测深度的不足便暴露无遗。

在万卡级算力集群中,单张 H100 的小时级成本已达数十美元,整集群日耗算力成本动辄百万。当每一分钟的 GPU 闲置都意味着真金白银的流失时,运维与算法团队真正需要回答的,远不止"GPU 温度是否正常"这一个问题:

  • 谁在消耗算力?——DCGM 仅能提供设备级聚合利用率,无法归因到具体进程、容器或 Pod,更无法穿透到团队、项目、任务维度,万卡集群的算力账单成了一笔糊涂账。
  • 算力是否真的有效?——利用率 80% 不等于有效计算 80%,可能是数据加载瓶颈,可能是 Kernel Launch 开销过大,也可能是大量小 Kernel 频繁发射导致调度开销占比过高。没有 CUDA 运行时的深度观测,80% 的利用率背后可能藏着巨大的算力浪费。
  • 投入产出比如何?——单卡数万、集群数亿的硬件投入,有多少时间在空转等待?训练任务的每瓦算力、每 token 成本是多少?传统监控只回答"硬件是否健康",却无法回答"算力投资是否高效"。
  • 性能瓶颈在哪一层?——训练吞吐下降、推理延迟升高时,是驱动版本问题、CUDA 库兼容性问题、网络通信瓶颈,还是业务代码的算法效率问题?没有分层穿透的观测能力,只能逐层盲猜、逐一排除,排障周期以天甚至周计。

DCGM Exporter 作为 NVIDIA 官方的 NVML 封装,在硬件指标采集层面无疑是可靠的,但它从底层就继承了 NVML 的全部边界——仅能提供硬件级计数器数据、NVIDIA 生态独占、缺乏 CUDA 运行时内省能力、无法实现进程级算力归因。当算力集群的规模从百卡跃迁至万卡,当 GPU 资源从团队专属变为多租户共享,当性能优化从"能用就行"转向"每瓦算力"的精细化运营,仅靠设备层监控已远远不够。算力基础设施的管理者,需要一套更深层、更标准化、更具穿透力的全链路可观测方案。

OpenLIT OTel GPU Collector 的出现,为万卡级算力集群的 GPU 可观测性提供了全新的技术路径。它以 OpenTelemetry 为标准化协议基座,通过 eBPF 技术深度穿透 CUDA 运行时,将 GPU 可观测的边界从传统的"设备硬件层"一路推进到"计算内核层"。而当这套深度采集能力与观测云的全链路可观测平台相结合,GPU 指标便不再是孤立的数据孤岛——它可以与应用性能 Trace、业务日志、基础设施指标在统一平台中实现全栈关联与跨层下钻,真正构建起从硬件到业务的完整观测链路。

观测云

观测云是一款专为 IT 工程师打造的全链路可观测产品,它集成了基础设施监控、应用程序性能监控和日志管理,为整个技术栈提供实时可观察性。这款产品能够帮助工程师全面了解端到端的用户体验追踪,了解应用内函数的每一次调用,以及全面监控云时代的基础设施。此外,观测云还具备快速发现系统安全风险的能力,为数字化时代提供安全保障。

为什么选观测云?

观测云原生支持 OTLP 协议接入,无需额外部署 Collector 集群;GPU 指标可与应用性能、日志、基础设施指标在同一平台关联分析;内置丰富的 Dashboard 模板和告警引擎,开箱即用。

可观测链路有三段:OpenLIT 负责采集,DataKit 负责接收 OTLP 并上报,观测云负责查询、展示和告警。


OpenLIT → DataKit → 观测云链路

采集到的数据分三层,各层的生效条件和价值不同:

层级 指标示例 生效条件与价值
设备层 hw.gpu.utilization、hw.gpu.memory、hw.gpu.power、hw.gpu.temperature 只要 Collector 能访问 GPU 就有数据。回答"GPU 是否在线、是否有容量压力"。
进程归因层 process.gpu.utilization、process.gpu.memory 要求 Collector 能看见主机进程(--pid=host)。回答"谁在用 GPU",支撑多租户计费和资源调度。
CUDA eBPF 层 gpu.kernel.launch.calls、gpu.memory.copies、gpu.sm_active 要求真实负载加载 libcudart,受内核版本、eBPF capability 和安全策略影响。回答"GPU 在干什么",支撑性能调优。

这种分层设计的核心思路是:不同层级对应不同的决策类型。设备层服务于运维响应(换卡、扩容),进程层服务于成本核算(调度、计费),内核层服务于性能优化(Kernel 融合、内存对齐)。越往下层,价值越高,但依赖条件也越苛刻。

接入步骤

接入过程分为五步:前置准备 → 配置 DataKit OTLP 接收 → 部署 OpenLIT Collector → 分层验证与排障 → 查询与告警配置。

1. 前置准备

部署前需确保主机已具备以下基础环境:

  • NVIDIA 驱动已安装且正常工作
  • Docker 或 Containerd 容器运行时
  • NVIDIA Container Toolkit(容器访问 GPU 必需)
  • DataKit 已部署且能正常上报到观测云

部署前先用一个临时容器确认 Docker 能访问 GPU(镜像按本机驱动兼容性选择):

docker run --rm --gpus all <兼容本机驱动的 CUDA 镜像> nvidia-smi

这一步失败就先修驱动或 Container Toolkit,OpenLIT 无法绕过底层问题。

2. 配置 DataKit OTLP 接收

编辑 /usr/local/datakit/conf.d/opentelemetry.conf(首次启用时从 samples/opentelemetry.conf.sample 复制,已有配置直接编辑不要覆盖):

[[inputs.opentelemetry]]
  customer_tags_all = true

  [inputs.opentelemetry.grpc]
    addr = "127.0.0.1:4317"
    max_payload = 16777216

customer_tags_all = true 会保留 OpenLIT 上报的全部 OTel attributes,便于用 GPU ID、进程、Kernel 名等 tag 自定义视图。

注意两点:

  • attribute key 中的点入库后变为下划线(hw.idhw_idcuda.kernel.namecuda_kernel_name
  • process.pidcuda.kernel.name 等高基数字段可能带来时序膨胀,生产环境可改为明确的 customer_tags 白名单

重启并确认监听:

sudo datakit service -R
ss -lntp | grep ':4317'

协议与端口必须成对:本文用 grpc 配 4317;改用 http/protobuf 则配 4318 且接收端要启用 OTLP/HTTP,两者不能混搭。跨主机或非 host 网络部署时,把 addr 改成 0.0.0.0:4317、Collector 端点改成 DataKit 的内网地址,用防火墙限制来源,不要把未认证的 OTLP 端口暴露到公网。

3. 部署 OpenLIT Collector

NVIDIA + Docker、同机直连 DataKit 的启动命令:

docker pull ghcr.io/openlit/otel-gpu-collector:latest

docker run -d \
  --name otel-gpu-collector \
  --restart unless-stopped \
  --network host \
  --gpus all \
  --pid=host \
  --cap-add BPF \
  --cap-add PERFMON \
  --ulimit memlock=-1:-1 \
  -e OTEL_SERVICE_NAME=openlit-otel-gpu-collector \
  -e OTEL_RESOURCE_ATTRIBUTES='deployment.environment=production,team=ml,host.name=gpu-host-01' \
  -e OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
  -e OTEL_EXPORTER_OTLP_PROTOCOL=grpc \
  -e OTEL_METRIC_EXPORT_INTERVAL=15000 \
  -e OTEL_GPU_EBPF_ENABLED=true \
  ghcr.io/openlit/otel-gpu-collector:latest

每个关键参数对应第一节的一层能力:

参数 对应层级 作用
--network host 链路层 连接宿主机 127.0.0.1:4317
--gpus all 设备层 访问 GPU 设备,获取 hw.gpu.* 指标
--pid=host 进程层 看见主机进程,实现进程归因和 libcudart 发现
BPF / PERFMON / memlock CUDA eBPF 层 eBPF 初始化所需权限

少哪个参数,对应层的数据就缺。

OTEL_METRIC_EXPORT_INTERVAL 单位是毫秒,默认 60000,官方对 GPU 主机建议 15000。OTEL_RESOURCE_ATTRIBUTES 至少给出稳定的 host.namedeployment.environment 和团队归属。生产环境验证后应固定镜像版本,不长期跟随 latest

启动后用 docker logs --tail 200 otel-gpu-collector 确认四件事:GPU 已发现、没有持续的 OTLP export error、eBPF 初始化没有 capability / memlock / perf event 报错、容器不在重启循环中。

4. 分层验证与排障

先验证设备层。 在观测云「指标」中对 otel_service 做一条最小查询,确认每块 GPU 每 15 秒持续上报:

M::`otel_service`:(last(`hw.gpu.up`) AS `GPU 在线`) [::15s] BY `host`,`hw_id`,`hw_name`

hw.gpu.up 连续出现即说明「GPU → OpenLIT → OTLP gRPC → DataKit → 观测云」整条链路成立。此时如果 CUDA Kernel/Memcpy 没有数据,不要回头排查 OTLP 端口,应检查工作负载与 eBPF 层。

CUDA eBPF 指标只有真实 CUDA 负载执行了对应操作才会产生(调用 Kernel 才有 gpu.kernel.launch.calls,执行 cudaMemcpy* 才有 gpu.memory.copies_*)。没有 CUDA workload 时设备层正常、CUDA 图表为空是预期行为。

指标缺数据时,按缺口直接定位层级:

现象 优先检查
所有 hw.gpu.* 都没有 GPU 设备映射、驱动、Container Toolkit、Collector 日志
设备指标有,进程指标没有 --pid=host、负载是否真的在用 GPU
进程指标有,Kernel/Memcpy/SM 没有 libcudart、BPF/PERFMON、memlock、AppArmor/Yama/perf event
Collector 有数据但观测云没有 OTLP 协议与端口、DataKit 监听、网络与 DataKit 日志
只缺某个 Memcpy 方向 负载没做该方向拷贝,不是采集故障

5. 查询与告警配置

写查询时最容易错的是把 Gauge、Counter、Histogram 当成同一种数据,对应三条规则:

比例值是 0..1,不是 0..100。 hw.gpu.utilizationprocess.gpu.utilizationgpu.sm_active 等在 Dashboard 用 percent_decimal 单位直接展示;Monitor 阈值按百分数写时要先乘 100。

Counter 看速率或增量,不看原值。 gpu.kernel.launch.calls 是累计值,画发射频率用 [::1m:rate];硬件错误用 [::5m:increase] 只盯新增。

Histogram 入库后展开为 _sum / _count / _bucket / _min / _max,字段名保留 OTel 点分名。

# Memcpy 吞吐(B/s)
M::`otel_service`:(sum(`gpu.memory.copies_sum`) AS `Memcpy 吞吐`) [::1m:rate] BY `cuda_memcpy_kind`

# Memcpy 调用率
M::`otel_service`:(sum(`gpu.memory.copies_count`) AS `Memcpy 调用率`) [::1m:rate] BY `cuda_memcpy_kind`

Dashboard 建议按四个问题分组组织,设备层与 CUDA 层分开,缺数据时能一眼定位层级:

  1. GPU 是否在线——在线状态、数量
  2. 是否有容量压力——利用率、显存、温度、功耗
  3. 谁在使用 GPU——进程名、PID、进程显存与利用率
  4. CUDA 行为是否健康——Kernel 发射率、Memcpy 吞吐与调用率、SM 活跃度
  5. 是否发生硬件或调度异常——硬件错误、节流原因

告警初始基线:

  • GPU 利用率 5 分钟均值低于 10% 且连续多个检测周期(成本告警)
  • 显存 usage / limit × 100 > 95%(容量告警)
  • 5 分钟 increase(hw.errors) > 0(硬件告警)
  • Kernel 发射率超基线并持续(工作负载信号)

其中 Kernel 发射频率没有跨业务通用阈值,训练、推理、批处理差异很大,先观察一段稳定业务基线再按 workload 分层设置。

接入效果

接入 OpenLIT + 观测云后,GPU 可观测性的价值体现在五个实战场景中——这些都是传统 DCGM 监控无法回答的问题。

场景一:哪个 CUDA Kernel 在吃我的 GPU?

启用 eBPF 后,采集器通过 uprobe 挂载到 cudaLaunchKernel 上,将 Kernel 发射转成按 Kernel 名分桶的指标。在观测云中可以直接查询:

# 整个集群中发射频率最高的 Top-10 Kernel
M::`otel_service`:(topk(10, sum(`gpu.kernel.launch.calls`) [::5m:rate] BY `cuda_kernel_name`))

对于 vLLM 部署,你将看到 flash_attention_kernelrms_norm_kernelpaged_attention_v2_kernel——这些名字与你 CUDA 库中编译的符号一一对应。这意味着 GPU 可观测性第一次从基础设施团队渗透到了 ML 工程师的工具箱:当 Kernel 发射频率异常升高时,直接指向 torch.compile 等优化方向,而不是运维层面的排查。

场景二:内存带宽被浪费了吗?

通过按方向拆分的 Memcpy 吞吐指标,可以判断数据加载是否高效:

  • 健康的训练循环会将数据固定在设备上,Memcpy 以 DeviceToDevice 为主
  • 如果 HostToDevice 占主导,说明数据加载器没有预热锁页内存,PCIe 总线在反复震荡
  • Memcpy 调用率高但吞吐低,说明是大量细碎的小拷贝——几乎总是一个性能 bug

传统监控只能看到"显存用了多少",但看不到"数据是怎么流动的"。eBPF 级别的 Memcpy 追踪让数据加载效率优化有了量化依据。

场景三:硬件健康的"金丝雀"信号

ECC 和 PCIe 重放错误是硬件故障的早期预警。采集器以 hw.errors 指标发射三类错误:corrected(可纠正)、uncorrected(不可纠正)、pcie_replay(PCIe 重放)。

不可纠正 ECC 错误出现非零增量,意味着这张卡应该退出资源池。单个 PCI 地址上的 PCIe 重放错误速率升高,意味着线缆或插槽接触不良。这些信号比温度告警更早、更准确地预测硬件故障——等到温度飙到 85°C 时,SM 时钟可能已经降频很久了。

总结

OpenLIT OTel GPU Collector + 观测云的组合,将 GPU 可观测性从传统的"设备温度监控"提升到了"全栈决策支持"的层面。其核心价值体现在三个维度:

深度:从设备层到内核层。 通过 eBPF 技术深入 CUDA 运行时,实现了 Kernel 级别的可观测性,让 ML 工程师能直接从指标定位优化方向,而不是靠猜测和 profiling。

标准:OTel 原生,无缝融入现有体系。 全程使用 OpenTelemetry 标准协议和语义约定,GPU 指标可以与应用 Trace、业务指标、日志在观测云中统一关联分析,不需要维护一套独立的 GPU 监控栈。

统一:一个平台,全栈可观测。 在观测云中,GPU 指标不是孤岛——你可以从应用延迟异常下钻到 GPU 利用率,再下钻到具体的 Kernel 发射模式,实现真正的全栈问题定位。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台