vLLM 高性能推理部署指南 / 11 - 监控与可观测性
11 - 监控与可观测性
建立完善的监控体系,实时掌握 vLLM 服务的运行状态和性能表现。
11.1 监控体系概览
11.1.1 可观测性三大支柱
┌───────────────────────┐
│ vLLM 可观测性 │
└───────────┬───────────┘
┌───────────────┼───────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 指标 │ │ 日志 │ │ 追踪 │
│ (Metrics) │ │ (Logging) │ │ (Tracing) │
│ │ │ │ │ │
│ Prometheus │ │ 结构化日志 │ │ OpenTelemetry│
│ Grafana │ │ ELK Stack │ │ Jaeger │
└──────────────┘ └──────────────┘ └──────────────┘
11.1.2 推荐监控栈
| 组件 | 工具 | 用途 |
|---|---|---|
| 指标收集 | Prometheus | 采集 vLLM 暴露的指标 |
| 指标可视化 | Grafana | 仪表板展示 |
| 日志收集 | Loki / ELK | 集中化日志管理 |
| 告警 | Alertmanager | 异常告警通知 |
| 追踪 | Jaeger | 请求链路追踪 |
11.2 Prometheus 指标
11.2.1 启用 Prometheus 指标
# 启动 vLLM 时启用指标(默认端口 8000 上的 /metrics 端点)
vllm serve Qwen/Qwen2.5-7B-Instruct \
--served-model-name qwen-7b
# 指标端点自动可用
curl http://localhost:8000/metrics
11.2.2 核心指标列表
请求指标
| 指标名 | 类型 | 说明 |
|---|---|---|
vllm:request_success | Counter | 成功完成的请求数 |
vllm:request_failure | Counter | 失败的请求数 |
vllm:request_inference_time_seconds | Histogram | 推理时间分布 |
vllm:request_queue_time_seconds | Histogram | 队列等待时间分布 |
vllm:request_prompt_tokens | Histogram | Prompt token 数分布 |
vllm:request_generation_tokens | Histogram | 生成 token 数分布 |
vllm:request_avg_generation_throughput | Histogram | 每请求吞吐量分布 |
系统指标
| 指标名 | 类型 | 说明 |
|---|---|---|
vllm:num_requests_running | Gauge | 正在运行的请求数 |
vllm:num_requests_waiting | Gauge | 等待中的请求数 |
vllm:num_requests_swapped | Gauge | 被 swap 的请求数 |
vllm:gpu_cache_usage_perc | Gauge | GPU 缓存使用率 |
vllm:cpu_cache_usage_perc | Gauge | CPU 缓存使用率 |
批处理指标
| 指标名 | 类型 | 说明 |
|---|---|---|
vllm:avg_prompt_throughput_toks_per_s | Gauge | 平均 prompt 处理吞吐量 |
vllm:avg_generation_throughput_toks_per_s | Gauge | 平均生成吞吐量 |
11.2.3 查看原始指标
# 查看所有指标
curl -s http://localhost:8000/metrics | head -100
# 过滤特定指标
curl -s http://localhost:8000/metrics | grep "vllm:num_requests"
# 格式化输出
curl -s http://localhost:8000/metrics | grep "vllm:gpu_cache"
11.3 Prometheus 配置
11.3.1 Prometheus 配置文件
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'vllm'
static_configs:
- targets: ['vllm-server:8000']
metrics_path: /metrics
scrape_interval: 5s # vLLM 建议更频繁的采集
# 可选:GPU 指标(通过 DCGM Exporter)
- job_name: 'nvidia-dcgm'
static_configs:
- targets: ['dcgm-exporter:9400']
11.3.2 使用 DCGM Exporter 监控 GPU
# 启动 DCGM Exporter(NVIDIA 官方 GPU 监控工具)
docker run -d \
--gpus all \
--name dcgm-exporter \
-p 9400:9400 \
nvcr.io/nvidia/k8s/dcgm-exporter:3.3.8-3.6.0-ubuntu22.04
DCGM Exporter 提供的 GPU 指标:
| 指标 | 说明 |
|---|---|
DCGM_FI_DEV_GPU_UTIL | GPU 利用率 (%) |
DCGM_FI_DEV_MEM_COPY_UTIL | 显存带宽利用率 (%) |
DCGM_FI_DEV_FB_USED | 已用显存 (MB) |
DCGM_FI_DEV_FB_FREE | 空闲显存 (MB) |
DCGM_FI_DEV_POWER_USAGE | 功率 (W) |
DCGM_FI_DEV_GPU_TEMP | 温度 (°C) |
11.4 Grafana 仪表板
11.4.1 推荐仪表板布局
┌─────────────────────────────────────────────────────────┐
│ vLLM 服务监控 │
├─────────────┬─────────────┬─────────────┬───────────────┤
│ 活跃请求数 │ 等待请求数 │ GPU缓存使用率│ 吞吐量 │
│ [Gauge] │ [Gauge] │ [Gauge] │ [Graph] │
│ 42 │ 156 │ 85% │ 1200 tok/s │
├─────────────┴─────────────┴─────────────┴───────────────┤
│ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ 请求吞吐量趋势 (tokens/s) │ │
│ │ ╱╲ ╱╲ │ │
│ │ ╱ ╲ ╱ ╲ ╱╲ │ │
│ │ ╱ ╲╱ ╲╱ ╲ │ │
│ │ ╱ ╲ │ │
│ └───────────────────────────────────────────────────┘ │
│ │
├────────────────────────┬────────────────────────────────┤
│ TTFT 延迟分布 │ TPOT 延迟分布 │
│ [Heatmap] │ [Heatmap] │
│ avg: 85ms, p99: 200ms│ avg: 15ms, p99: 45ms │
├────────────────────────┼────────────────────────────────┤
│ GPU 利用率 │ 显存使用 │
│ [Time Series] │ [Stacked Area] │
│ 95% │ Model 14GB + KV 46GB │
└────────────────────────┴────────────────────────────────┘
11.4.2 关键 PromQL 查询
# 吞吐量(每秒生成的 token 数)
vllm:avg_generation_throughput_toks_per_s{model="qwen-7b"}
# 请求数
vllm:num_requests_running{model="qwen-7b"}
vllm:num_requests_waiting{model="qwen-7b"}
# GPU 缓存使用率
vllm:gpu_cache_usage_perc{model="qwen-7b"}
# 请求成功率
rate(vllm:request_success{model="qwen-7b"}[5m]) /
(rate(vllm:request_success{model="qwen-7b"}[5m]) + rate(vllm:request_failure{model="qwen-7b"}[5m]))
# P99 推理延迟
histogram_quantile(0.99, rate(vllm:request_inference_time_seconds_bucket{model="qwen-7b"}[5m]))
# 平均队列等待时间
rate(vllm:request_queue_time_seconds_sum{model="qwen-7b"}[5m]) /
rate(vllm:request_queue_time_seconds_count{model="qwen-7b"}[5m])
# GPU 利用率(DCGM)
DCGM_FI_DEV_GPU_UTIL{gpu="0"}
# GPU 温度
DCGM_FI_DEV_GPU_TEMP{gpu="0"}
11.5 日志管理
11.5.1 vLLM 日志配置
# 设置日志级别
export VLLM_LOGGING_LEVEL=INFO # DEBUG, INFO, WARNING, ERROR
# 启动时的配置
vllm serve model \
--disable-log-requests # 禁用逐请求日志(高并发时减少日志量)
11.5.2 结构化日志示例
# 自定义日志处理
import logging
import json
from datetime import datetime
class JSONFormatter(logging.Formatter):
def format(self, record):
log_data = {
"timestamp": datetime.utcnow().isoformat(),
"level": record.levelname,
"message": record.getMessage(),
"module": record.module,
}
return json.dumps(log_data, ensure_ascii=False)
# 配置
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger = logging.getLogger("vllm")
logger.addHandler(handler)
11.6 告警配置
11.6.1 Alertmanager 规则
# vllm_alerts.yml
groups:
- name: vllm_alerts
rules:
# GPU 缓存使用率过高
- alert: VLLMHighCacheUsage
expr: vllm:gpu_cache_usage_perc > 0.95
for: 5m
labels:
severity: warning
annotations:
summary: "vLLM GPU 缓存使用率超过 95%"
description: "模型 {{ $labels.model }} 的 GPU 缓存使用率已达 {{ $value | humanizePercentage }}"
# 等待队列过长
- alert: VLLMHighQueueLength
expr: vllm:num_requests_waiting > 500
for: 2m
labels:
severity: critical
annotations:
summary: "vLLM 等待队列过长"
description: "模型 {{ $labels.model }} 有 {{ $value }} 个请求等待中"
# 吞吐量下降
- alert: VLLMLowThroughput
expr: vllm:avg_generation_throughput_toks_per_s < 100
for: 5m
labels:
severity: warning
annotations:
summary: "vLLM 吞吐量过低"
description: "模型 {{ $labels.model }} 吞吐量仅 {{ $value }} tokens/s"
# 请求失败率高
- alert: VLLMHighFailureRate
expr: rate(vllm:request_failure[5m]) / (rate(vllm:request_success[5m]) + rate(vllm:request_failure[5m])) > 0.05
for: 3m
labels:
severity: critical
annotations:
summary: "vLLM 请求失败率超过 5%"
# GPU 温度过高
- alert: GPUHighTemperature
expr: DCGM_FI_DEV_GPU_TEMP > 85
for: 5m
labels:
severity: warning
annotations:
summary: "GPU 温度过高: {{ $value }}°C"
# 推理延迟过高
- alert: VLLMHighLatency
expr: histogram_quantile(0.99, rate(vllm:request_inference_time_seconds_bucket[5m])) > 10
for: 5m
labels:
severity: warning
annotations:
summary: "vLLM P99 推理延迟超过 10 秒"
11.6.2 告警通知配置
# alertmanager.yml
route:
group_by: ['alertname', 'severity']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'default'
routes:
- match:
severity: critical
receiver: 'pager'
receivers:
- name: 'default'
webhook_configs:
- url: 'http://dingtalk-webhook:8060/dingtalk/ops/send'
- name: 'pager'
webhook_configs:
- url: 'http://pagerduty-webhook/alert'
11.7 自定义指标导出
11.7.1 应用层指标
# custom_metrics.py
"""自定义应用层监控指标"""
from prometheus_client import Counter, Histogram, Gauge, start_http_server
import time
# 定义自定义指标
request_counter = Counter(
'app_llm_requests_total',
'Total LLM requests',
['endpoint', 'model', 'status']
)
request_latency = Histogram(
'app_llm_request_latency_seconds',
'LLM request latency',
['endpoint', 'model'],
buckets=[0.1, 0.5, 1.0, 2.0, 5.0, 10.0, 30.0, 60.0]
)
active_users = Gauge(
'app_active_users',
'Number of active users'
)
# 中间件包装
def monitor_request(func):
def wrapper(*args, **kwargs):
start = time.time()
try:
result = func(*args, **kwargs)
request_counter.labels(
endpoint="chat",
model="qwen-7b",
status="success"
).inc()
return result
except Exception as e:
request_counter.labels(
endpoint="chat",
model="qwen-7b",
status="error"
).inc()
raise
finally:
request_latency.labels(
endpoint="chat",
model="qwen-7b"
).observe(time.time() - start)
return wrapper
# 启动指标服务器
start_http_server(9090)
11.8 业务场景
场景一:容量规划
监控指标 → 识别瓶颈 → 容量规划
关键指标趋势:
- 吞吐量:峰值是否接近上限?
- GPU 缓存:是否经常 > 90%?
- 队列长度:是否持续增长?
- 延迟:是否超出 SLA?
决策:
- 吞吐量饱和 → 增加实例
- GPU 缓存不足 → 增加 GPU / 减小 max_model_len
- 队列过长 → 扩容或限流
场景二:故障排查
监控发现异常 → 快速定位原因
1. 延迟突增
→ 检查 GPU 利用率(是否 100%?)
→ 检查队列长度(是否积压?)
→ 检查日志(是否有错误?)
2. 吞吐量下降
→ 检查 GPU 温度(是否过热降频?)
→ 检查请求分布(prompt 是否变长?)
→ 检查 swap(是否频繁 swap?)
3. 请求失败
→ 检查错误日志
→ 检查 OOM
→ 检查模型是否加载成功
11.9 完整监控部署
11.9.1 Docker Compose 监控栈
# docker-compose.monitoring.yml
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- ./vllm_alerts.yml:/etc/prometheus/vllm_alerts.yml
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana
- ./grafana/dashboards:/etc/grafana/provisioning/dashboards
- ./grafana/datasources:/etc/grafana/provisioning/datasources
alertmanager:
image: prom/alertmanager:latest
ports:
- "9093:9093"
volumes:
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
dcgm-exporter:
image: nvcr.io/nvidia/k8s/dcgm-exporter:3.3.8-3.6.0-ubuntu22.04
ports:
- "9400:9400"
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
volumes:
grafana-data:
11.10 注意事项
指标采样频率:vLLM 指标的采集间隔建议 5-10 秒。过于频繁的采集会增加开销。
指标基数:避免在 labels 中使用高基数(如 request_id),否则会导致 Prometheus 内存爆炸。
GPU 监控:除了 vLLM 自身指标,务必监控 GPU 硬件指标(温度、功耗、ECC 错误)。
日志量控制:高并发场景下,逐请求日志会产生大量 I/O。建议使用
--disable-log-requests。
11.11 扩展阅读
上一章:10 - 性能调优 | 下一章:12 - Kubernetes 部署