用 Grafana 和 Prometheus 监控 vLLM 生产环境
在服务器上跑大语言模型是一回事,实时了解模型内部运行状态是另一回事。当你在 A100 服务器上用 vLLM 部署 Qwen3.6-27B 时,你需要实时掌握 GPU 利用率、请求吞吐量、token 生成速率、队列深度等关键指标。
本文记录我们在两台 A100 服务器上部署 vLLM 监控面板的完整过程,涵盖架构设计、部署步骤、常见陷阱和关键指标解读。

为什么要监控 vLLM?
vLLM 是大语言模型推理的行业标准引擎,从本地部署到云端大规模服务都在使用。但如果没有监控,你就是在盲飞:
- GPU 显存泄漏可能悄无声息地填满 80GB A100 显存,导致长时间运行后 OOM 崩溃
- 请求队列堆积意味着用户在等待,但你可能直到用户投诉才知道
- Token 生成速率下降可能暗示硬件问题、散热降频或模型异常
- 前缀缓存命中率告诉你优化策略是否真正生效
好消息是:vLLM 内置了 Prometheus 指标端点——386 个指标,通过 /metrics 端点直接暴露。你只需要 Prometheus 来采集,Grafana 来可视化。
架构概览
监控栈非常简单轻量:
vLLM (端口 8391) → /metrics 端点 (Prometheus 格式,386 个指标)
↓
Prometheus (端口 9090) → 每 15 秒采集一次 /metrics
↓
Grafana (端口 3000) → 使用 vLLM Monitoring V2 面板可视化 (ID: 24756)
三个组件运行在同一台服务器上。vLLM 提供服务,Prometheus 采集指标,Grafana 渲染面板。整个栈只需要几个 Docker 容器。
第一步:发现 vLLM 内置指标
vLLM 在 http://<服务器>:8391/metrics 暴露 Prometheus 格式的指标。一个简单的 curl 就能发现 386 个独立指标,覆盖:
- GPU 利用率:显存使用、KV cache 分配、GPU 利用率百分比
- 请求指标:总请求数、运行中/排队/交换中的请求数、请求延迟
- Token 指标:每秒生成 token 数、每秒 prompt token 数、迭代 token 数
- 缓存指标:前缀缓存命中率、block 驱逐计数
- 吞吐量:每秒请求数、每秒 token 数
- MTP(多 Token 预测):推测 token 接受率
指标带有完整的 Prometheus 标签,便于在 Grafana 中过滤和聚合。
第二步:部署 Prometheus
Prometheus 以 Docker 容器方式部署,使用 host 网络模式——这很关键,因为容器需要访问宿主机上 vLLM 的 /metrics 端点。
docker run -d \
--name prometheus \
--network host \
-v ~/monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml \
-v ~/monitoring/prometheus/data:/prometheus \
prom/prometheus:latest
配置文件 prometheus.yml 指定 vLLM 指标端点:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'vllm'
static_configs:
- targets: ['localhost:8391']
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
关键要点:使用 --network host 是必须的。不使用的话,容器无法访问 localhost:8391,因为 Docker 默认桥接网络会将容器与宿主机的回环接口隔离。
第三步:部署 Grafana
Grafana 提供可视化层。我们使用官方 Docker 镜像并挂载持久化存储:
docker run -d \
--name grafana \
--network host \
-v ~/monitoring/grafana:/var/lib/grafana \
-e GF_SECURITY_ADMIN_PASSWORD=admin \
grafana/grafana:latest
常见问题:Grafana 数据目录必须有写入权限。如果遇到错误,执行:
chmod 777 ~/monitoring/grafana
端口冲突:在办公室 A100 服务器上,端口 3000 已被 Node.js 进程占用。解决方案是将 Grafana 映射到 3001 端口:
-p 3001:3000
第四步:配置数据源
Grafana 启动后,通过 API 添加 Prometheus 数据源:
curl -s -X POST http://localhost:3000/api/datasources \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{
"name": "Prometheus",
"type": "prometheus",
"url": "http://localhost:9090",
"access": "proxy",
"isDefault": true
}'
在 http://<服务器>:3000 使用 admin/admin 登录验证连接。
第五步:导入 vLLM 监控面板
Grafana 社区有一个优秀的 vLLM 监控面板——ID 24756(vLLM Monitoring V2),开箱即用地提供全面的可视化。
重要:面板必须通过 /api/dashboards/db API 端点导入,而不是已废弃的 /api/dashboards/import。后者会静默失败。
curl -s -X POST http://localhost:3000/api/dashboards/db \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d @vllm-dashboard.json
面板包含以下监控项:
- GPU 显存使用趋势
- 请求吞吐量(请求/秒)
- Token 生成速率(token/秒)
- 队列深度和延迟百分位
- KV Cache 利用率
- 前缀缓存命中率
- MTP 推测 token 接受率
- 活跃/运行中/排队中的请求数
两台服务器的部署实践
我们在两台不同的 A100 服务器上部署了这套监控栈,每台都遇到了独特的挑战:
服务器 1:双 A100 服务器 (172.24.217.58)
- 系统:Ubuntu,预装 Docker
- vLLM:GPU 1 上运行 Qwen3.6-27B,端口 8391,FP8 量化
- Grafana:端口 3000(默认)
- 面板地址:http://172.24.217.58:3000
- 备注:部署顺利,通过代理(127.0.0.1:7897)访问 Docker Hub
服务器 2:办公室 A100 服务器 (172.24.168.225)
- 系统:Ubuntu 22.04,未预装 Docker
- Docker:通过
apt install docker.io安装(版本 29.1.3) - Docker Hub:直连超时,配置镜像加速器(docker.1ms.run)
- 端口冲突:3000 端口被 Node.js 占用 → Grafana 改用 3001 端口
- vLLM:Qwen3.6-27B FP8,max_model_len=200000
- 面板地址:http://172.24.168.225:3001
- 备注:需要安装 Docker、配置镜像、调整端口
关键指标解读
运行面板数天后,我们最关注的指标如下:
| 指标 | 为什么重要 | 告警阈值 |
|---|---|---|
| GPU 显存使用 | 及早发现显存泄漏 | >85% |
| 请求队列长度 | 用户体验指标 | >10 等待中 |
| Token/秒 | 吞吐量健康检查 | <基线 50% |
| 前缀缓存命中率 | 优化效果追踪 | 关注趋势 |
| 请求延迟 P99 | 尾部延迟监控 | >中位数 2 倍 |
| KV Cache Block 数 | 显存压力信号 | >90% 已分配 |
常见陷阱与解决方案
1. Docker 网络模式
问题:容器无法访问 localhost 上的 vLLM。
解决:Prometheus 和 Grafana 容器都使用 --network host。
2. Grafana 数据目录权限
问题:Grafana 启动时权限拒绝报错。
解决:启动前对挂载的数据目录执行 chmod 777。
3. 面板导入 API
问题:面板导入静默失败。
解决:使用 /api/dashboards/db 端点,而非已废弃的 /api/dashboards/import。
4. Docker Hub 超时
问题:docker pull 在 GFW 后超时挂起。
解决:在 /etc/docker/daemon.json 中配置镜像加速器。
5. 端口冲突
问题:默认端口(3000、9090)已被占用。
解决:用 ss -tlnp | grep <端口> 检查,改用其他端口。
部署成果
监控面板提供了 vLLM 运行的实时可见性。部署后的关键观察:
- FP8 量化将 GPU 显存使用从 ~69GB(BF16)降至 ~20GB,留有充足余量
- 前缀缓存对重复 prompt 显示高命中率,显著降低延迟
- MTP 推测解码达到约 60% 的 token 接受率,提升吞吐量
- 请求延迟在中等负载下保持稳定,P99 通常在 2 秒以内

总结
在生产环境中监控 vLLM 并不需要复杂的架构。借助内置的 /metrics 端点、Prometheus 和 Grafana 社区面板,你可以在 30 分钟内部署一套完整的监控栈。
关键经验:
- 使用 Docker host 网络模式实现容器与宿主机通信
- 通过
/api/dashboards/dbAPI 导入面板 - 设置正确的 Grafana 数据目录权限
- 防火墙后配置 Docker 镜像加速器
- 关注核心指标——GPU 显存、队列深度和 token 吞吐量是你的北极星指标
有了这套方案,你可以在问题变成故障之前发现它们,并有数据支撑 LLM 服务基础设施的持续优化。
故障排除:Datasource ${DS_PROMETHEUS} was not found
导入 Grafana Dashboard(ID 24756)后,如果面板报错:
PanelQueryRunner Error {message: 'Datasource ${DS_PROMETHEUS} was not found'}
原因:Dashboard JSON 中的数据源引用使用了变量 ${DS_PROMETHEUS},但 Grafana 实例中没有定义该模板变量,导致无法解析为实际的数据源 UID。
解决方案:将 Dashboard JSON 中的 ${DS_PROMETHEUS} 替换为 Prometheus 数据源的实际 UID。
# 1. 获取 Prometheus 数据源 UID
curl -s -u admin:your_password http://localhost:3000/api/datasources | python3 -m json.tool
# 找到 "uid": "xxxxxxxxx" 的值
# 2. 导出 Dashboard JSON
curl -s -u admin:your_password http://localhost:3000/api/dashboards/uid/vllm-master-v2 > dashboard.json
# 3. 替换变量(用 python3 处理 JSON)
python3 -c "
import json
with open('dashboard.json', 'r') as f:
data = json.load(f)
json_str = json.dumps(data)
json_str = json_str.replace('\${DS_PROMETHEUS}', 'YOUR_PROMETHEUS_UID')
with open('dashboard_fixed.json', 'w') as f:
f.write(json_str)
print('Replaced successfully')
"
# 4. 重新导入
curl -s -u admin:your_password -X POST http://localhost:3000/api/dashboards/db \
-H 'Content-Type: application/json' \
-d @dashboard_fixed.json
预防:导入 Dashboard 前,确保 Grafana 中已配置 Prometheus 数据源,且 Dashboard JSON 中的变量引用能正确解析。如果使用的是 Grafana 官方 Dashboard(如 ID 24756),建议导入后检查数据源引用是否正确。
有问题或建议?欢迎在 GitHub 上交流,或加入我们的 Discord 社区。