NVIDIA NCP(NVIDIA Cloud Accelerator Platform)
这段架构在讲什么
整套体系建立在三类信号上:
- Logs(日志):应用、系统服务、硬件产生的离散事件记录。
- Metrics(指标):可量化的系统行为,比如延迟、吞吐、GPU 利用率。
- Traces(链路追踪):一个请求或操作在分布式系统里端到端走过的路径。
数据流可以拆成三层:
1. 数据产生与采集
数据来自三个源头:
- 应用层:通过 OpenTelemetry SDK 上报 metrics 和 traces。
- 基础设施层:系统日志,以及通过 DCGM Exporter 采集的 GPU 遥测(NVIDIA Data Center GPU Manager,专门暴露显存、温度、功耗、SM 利用率、ECC 错误等)。
- 网络设备层:通过 gNMI / OpenConfig 采集 fabric 健康度(这是网络设备的流式遥测标准,比传统 SNMP 轮询实时性好得多)。
每个节点上跑一个 OTel Collector Agent ,在本地做批处理和数据富化(打标签、补充节点/集群元信息),再用 OTLP 协议转发给网关。本地预处理这一步是为了减少网络开销、就近打标。
2. 接入与处理
OTel Collector Gateway 是集中处理层,干四件事:过滤、采样、转换、扇出路由(同一份数据可以同时发往多个后端)。后面挂一个 Kafka 作为流处理缓冲层,夹在网关和存储之间。它的作用是削峰填谷------当大型 GPU 集群突发流量时,Kafka 顶住洪峰,不让后端存储被打垮。
3. 存储后端
存储分热路径和冷路径两条:
- 热路径:用专用存储做实时监控、告警、事故响应。Loki 存日志、Tempo 存 traces、Prometheus 存 metrics。保留期 1~2 周。
- 冷路径 :写入遥测数据湖(对象存储上的 Parquet 列式文件),用于长期分析、容量规划、历史回溯。保留期几个月到几年。
这个热冷分离是成本和性能的折中:热路径快但贵,只留近期数据;冷路径慢但便宜,长期归档。
一套可落地的部署方案
下面给一套从环境准备到上线的完整方案,按 Kubernetes 部署来设计(AI 数据中心基本都跑 K8s + GPU Operator),如果你们是裸金属或别的编排我可以再调整。
整体拓扑
[每个节点]
应用(OTel SDK) ─┐
DCGM Exporter ──┼─→ OTel Collector Agent (DaemonSet) ──OTLP──┐
Node logs ──────┘ │
网络设备(gNMI) ──→ OTel Collector (gNMI receiver) ───────────┤
▼
OTel Collector Gateway (Deployment, 多副本)
│
┌────────────┴────────────┐
▼ ▼
Kafka 集群 (可直连,小规模时)
│
┌───────────────────────┼───────────────────────┐
▼ ▼ ▼
热路径消费者 热路径消费者 冷路径消费者(Sink)
│ │ │
Prometheus Loki / Tempo Parquet 写入器
(Mimir/Thanos) → 对象存储数据湖
│ │
└────────────┬───────────┘
▼
Grafana (统一展示 + 告警)
阶段一:环境准备
先把底座准备好。Kubernetes 集群上装好 NVIDIA GPU Operator(它会自动部署 DCGM Exporter,省去手动装的麻烦)。规划好三套独立的资源域:采集层、消息层、存储层,建议分别用不同的 node pool 或 namespace 隔离,避免遥测系统自身抢占训练任务的资源。GPU 节点本身要预留一点 CPU/内存给 Agent,否则采集会和训练抢资源。
对象存储先选好------可以是自建 MinIO/Ceph,也可以是云厂商的 S3 兼容存储。这个是冷路径的底座,也是 Loki / Tempo 的后端,统一用对象存储能大幅降成本。
阶段二:采集层(Agent)
用 OpenTelemetry Collector 的 DaemonSet 模式,每个节点一个 Agent。关键配置:
yaml
# otel-agent-config.yaml (节选核心思路)
receivers:
otlp: # 接收应用 SDK 上报
protocols:
grpc:
http:
prometheus: # 抓 DCGM Exporter 暴露的 metrics
config:
scrape_configs:
- job_name: 'dcgm'
scrape_interval: 10s
static_configs:
- targets: ['localhost:9400']
filelog: # 采集节点日志
include: [/var/log/pods/*/*/*.log]
processors:
batch: # 本地批处理,降低网络开销
timeout: 5s
send_batch_size: 1024
resourcedetection: # 自动补充 k8s/host 元数据
detectors: [env, system, k8s]
resource: # 打标:集群、节点、租户
attributes:
- key: cluster
value: "ai-dc-prod-01"
action: upsert
exporters:
otlp:
endpoint: "otel-gateway:4317"
tls:
insecure: false # 生产环境务必开 TLS
service:
pipelines:
metrics:
receivers: [otlp, prometheus]
processors: [resourcedetection, resource, batch]
exporters: [otlp]
logs:
receivers: [otlp, filelog]
processors: [resourcedetection, resource, batch]
exporters: [otlp]
traces:
receivers: [otlp]
processors: [resourcedetection, resource, batch]
exporters: [otlp]
网络设备的 gNMI 采集单独跑一组 Collector(不是 DaemonSet,因为网络设备数量有限),用 OTel 的 gnmi receiver 或独立的 gnmic 工具采集后转 OTLP。
DCGM 这里要重点关注的指标:DCGM_FI_DEV_GPU_UTIL(利用率)、DCGM_FI_DEV_GPU_TEMP(温度)、DCGM_FI_DEV_POWER_USAGE(功耗)、DCGM_FI_DEV_FB_USED(显存)、DCGM_FI_DEV_NVLINK_*(NVLink 流量)、DCGM_FI_DEV_XID_ERRORS(XID 错误,这个对排查训练崩溃极关键)。
阶段三:网关层(Gateway)
用 Deployment 模式部署,多副本 + HPA 自动扩缩。前面挂一个 Service 做负载均衡。网关负责采样和扇出:
yaml
# otel-gateway-config.yaml (节选核心思路)
processors:
tail_sampling: # 对 traces 做尾部采样,只留有价值的
policies:
- name: errors
type: status_code
status_code: {status_codes: [ERROR]}
- name: slow
type: latency
latency: {threshold_ms: 1000}
- name: baseline
type: probabilistic
probabilistic: {sampling_percentage: 5}
filter: # 丢弃噪声指标
metrics:
exclude:
match_type: regexp
metric_names: ['.*_bucket_noise.*']
exporters:
kafka: # 主路径:写入 Kafka 缓冲
brokers: ["kafka-0:9092","kafka-1:9092","kafka-2:9092"]
topic: "otel-metrics"
encoding: otlp_proto
service:
pipelines:
metrics:
receivers: [otlp]
processors: [filter, batch]
exporters: [kafka]
traces:
receivers: [otlp]
processors: [tail_sampling, batch]
exporters: [kafka]
尾部采样放在网关而不是 Agent,是因为只有汇聚到一处才能基于整条 trace 的全局信息(是否报错、是否慢)来决定留不留。
阶段四:缓冲层(Kafka)
Kafka 按信号类型分 topic:otel-logs、otel-metrics、otel-traces。分区数按峰值吞吐和消费者并行度来定,AI 集群突发性强,分区给宽裕些。副本因子至少 3,保证不丢数据。保留期设短(比如 24~48 小时)即可,它只是缓冲不是存储。给 Kafka 配独立的高 IOPS 磁盘。
阶段五:存储层
热路径(保留 1~2 周):
- Metrics:Prometheus,但单机 Prometheus 扛不住上千 GPU 的量,直接上 Grafana Mimir 或 Thanos 做水平扩展和长期存储分层。
- Logs:Loki,后端指向对象存储。
- Traces:Tempo,后端同样指向对象存储。
从 Kafka 到这些后端,用对应的 Kafka 消费者(OTel Collector 也能反过来从 Kafka 读再写后端,配 kafka receiver)。
冷路径 (保留数月到数年):单独一组消费者从 Kafka 读全量数据,转成 Parquet 写对象存储,按 日期/集群/信号类型 分区存放。这样后续用 Trino / Spark / DuckDB 直接查数据湖做容量规划和历史分析。可以用 OTel 的 file exporter 或专门的写入服务。
阶段六:展示与告警
Grafana 作为统一门户,接 Mimir/Prometheus、Loki、Tempo 三个数据源。利用 trace ID 做日志-链路-指标的跳转关联(Grafana 原生支持 trace-to-logs、trace-to-metrics)。
告警规则重点放在:GPU 温度/功耗越限、XID 错误、显存 OOM、NVLink/InfiniBand 链路降速或丢包、训练吞吐异常下降、节点 NCCL 通信超时。告警走 Alertmanager 分级路由到值班系统。
上线建议与几个坑
按热路径优先、冷路径其次的顺序上:先把"采集 → 网关 → Kafka → Prometheus/Loki/Tempo → Grafana"打通,能看实时监控和告警了,再补冷路径数据湖。
几个容易踩的点提前说一下:
- 基数爆炸:GPU 集群很容易因为标签维度太多(每张卡 + 每个 pod + 每个租户)导致 Prometheus 时间序列基数爆炸,内存撑爆。一定要在 Agent/Gateway 层控制标签维度,该聚合的聚合。
- 采集自身抢资源:Agent 跑在 GPU 节点上要设 resource limits,别让它影响训练。
- 关联三把钥匙要落实:时间戳要靠 NTP/PTP 严格同步(跨上千节点尤其重要),trace ID 要在应用埋点时正确透传,资源 ID 命名规范要统一,否则后期关联和租户归因会很痛苦。
- 安全:OTLP 链路、Kafka、对象存储访问全程开 TLS + 认证,多租户场景下遥测数据本身就是敏感信息。这一点架构原文没强调,但生产环境必须做。