生产级监控怎么做,Prometheus 加 DCGM 守护推理服务
从“黑盒”到透明:构建推理服务的可观测性防线
在生产环境跑通大模型推理只是第一步,真正的挑战在于如何让服务长期稳定运行。很多团队在上线初期只关注吞吐量(Token/s),却忽略了可观测性体系的搭建,结果一旦遇到显存泄漏或长尾延迟,只能对着黑盒般的日志抓瞎。基于我们在 AMD Instinct GPU 配合 ROCm 7.x 部署 vLLM 的实战经验,一套完善的监控与日志系统不是锦上添花,而是防止服务雪崩的最后一道防线。本文将分享如何从零构建这套体系,让 GPU 的每一次心跳都清晰可见。
搭建 Prometheus + Grafana 监控栈
监控的核心在于数据采集的实时性与准确性。在 ROCm 生态下,我们不再依赖传统的 NVIDIA-smi 轮询脚本,而是采用 DCGM Exporter(Data Center GPU Manager)作为标准数据源。虽然 DCGM 最初是为 NVIDIA 设计,但在适配 ROCm 的发行版中,它同样能高效采集 Instinct GPU 的核心指标。
首先,需要在宿主机或容器侧部署 DCGM Exporter。如果你使用 Kubernetes,可以通过 Helm Chart 一键安装;若是裸机部署,直接运行官方提供的 Docker 镜像即可。关键在于确保 exporter 能正确读取 /dev/dri 下的设备节点。启动命令示例如下:
docker run -d --gpus all --rm -p 9400:9400 \
--name dcgm-exporter \
nvcr.io/nvidia/k8s/dcgm-exporter:3.3.6-3.4.0-ubuntu22.04
注:请根据实际 ROCm 版本选择兼容的 exporter 镜像,部分社区维护版本已支持 AMD 后端。
接下来是 Prometheus 的配置。在 prometheus.yml 中添加一个新的 scrape job,指向 exporter 暴露的 9400 端口。为了区分不同业务线的推理实例,建议利用 relabel_configs 添加自定义标签,如 service_name 或 model_version。
scrape_configs:
- job_name: 'gpu-inference'
static_configs:
- targets: ['localhost:9400']
relabel_configs:
- source_labels: [__address__]
target_label: instance
replacement: 'inference-node-01'
数据入库后,Grafana 的可视化面板就能发挥价值了。我们推荐导入社区通用的 DCGM 仪表盘模板,并针对推理场景做微调。重点关注的指标包括:
- DCGM_FI_DEV_GPU_TEMP:实时监控显卡温度,防止过热降频。
- DCGM_FI_DEV_POWER_USAGE:观察功耗波动,异常飙升往往意味着死循环或计算风暴。
- DCGM_FI_DEV_SM_ACTIVE:流多处理器活跃度,反映算力利用率。
- DCGM_FI_DEV_FB_USED:显存使用率,这是最核心的生命线指标。
显存告警阈值与 OOM 预防策略
在生产环境中,显存溢出(OOM)是导致推理服务崩溃的头号杀手。vLLM 虽然通过 PagedAttention 优化了显存管理,但面对突发流量或长上下文请求,显存仍可能瞬间打满。
根据我们的压测数据,将告警阈值设置在 95% 是一个经过验证的“安全线”。当 DCGM_FI_DEV_FB_USED 持续 1 分钟超过该比例时,必须立即触发告警。这并非危言耸听:一旦显存达到 100%,Linux 内核的 OOM Killer 会随机杀死进程,通常首当其冲的就是占用显存最大的推理服务,导致服务中断甚至节点重启。
在 Grafana 中配置 Alertmanager 规则时,建议采用分层告警策略:
- Warning 级别:显存使用率 > 85% 持续 5 分钟。此时无需人工介入,但应触发自动扩容脚本或限制新请求接入。
- Critical 级别:显存使用率 > 95% 持续 1 分钟。立即发送电话或短信通知值班人员,并尝试自动重启异常 Pod 以释放碎片。
此外,务必在 vLLM 启动参数中预留缓冲空间。不要将 --gpu-memory-utilization 设置为激进的 0.95 或 0.98,建议控制在 0.90 - 0.92 之间。这部分预留的显存不仅能应对驱动层面的瞬时开销,还能为监控探针和日志收集进程提供生存空间,避免“监控本身把服务挤崩”的尴尬局面。
结构化日志与长尾延迟分析
监控指标告诉我们“发生了什么”,而日志则揭示“为什么发生”。vLLM 默认的标准输出虽然信息丰富,但在高并发下难以检索和分析。我们需要将其重定向到结构化日志系统(如 ELK Stack 或 Loki)。
具体操作上,可以通过修改 logging 配置,将输出格式强制设为 JSON。这样,每一行日志都包含清晰的键值对,便于提取关键字段:
# vLLM 启动时的 logging 配置示例
import logging
import json
class JSONFormatter(logging.Formatter):
def format(self, record):
log_data = {
"timestamp": self.formatTime(record),
"level": record.levelname,
"request_id": getattr(record, 'request_id', 'N/A'),
"latency_ms": getattr(record, 'latency_ms', 0),
"prompt_tokens": getattr(record, 'prompt_tokens', 0),
"generated_tokens": getattr(record, 'generated_tokens', 0),
"message": record.getMessage()
}
return json.dumps(log_data)
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logging.getLogger("vllm").addHandler(handler)
有了结构化日志,分析长尾延迟(Long-tail Latency)就变得有的放矢。我们可以编写查询语句,筛选出 latency_ms 大于 P99 阈值的请求,并关联其 prompt_tokens 和 generated_tokens 字段。
在实际案例中,我们发现某类特定长度的输入(例如接近 block_size 整数倍的 prompt)会导致显著的延迟抖动。通过分析日志,定位到是显存块分配策略在边界条件下的效率下降。基于此,我们调整了前端的截断策略,对超长输入进行智能切片,并在后端优化了 --block-size 参数,最终将 P99 延迟降低了 40%。
定期复盘与资源泄漏排查
系统上线并不意味着工作结束。定期的日志复盘是发现隐蔽问题的关键手段。有些资源泄漏(如 KV Cache 未完全释放、句柄泄露)不会立即触发告警,但会随着时间推移逐渐侵蚀系统稳定性。
建议每周进行一次深度日志审计:
- 检查是否有频繁的重试请求,这可能暗示客户端超时设置不合理。
- 对比不同时段的显存基线,若发现基线随时间缓慢上升,极可能存在内存泄漏。
- 统计各类错误码的分布,识别偶发的算子执行失败或网络超时。
通过这种“监控 + 日志 + 复盘”的闭环,我们不仅能快速响应故障,更能主动优化架构,让推理服务在复杂的生产环境中保持长期的健壮与高效。毕竟,稳定的服务才是业务增长的坚实底座。
200小时GPU算力已就位,快来领取:https://marketing.csdn.net/questions/Q2604140858304426315?utm_source=AIpaper

更多推荐


所有评论(0)