强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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_successCounter成功完成的请求数
vllm:request_failureCounter失败的请求数
vllm:request_inference_time_secondsHistogram推理时间分布
vllm:request_queue_time_secondsHistogram队列等待时间分布
vllm:request_prompt_tokensHistogramPrompt token 数分布
vllm:request_generation_tokensHistogram生成 token 数分布
vllm:request_avg_generation_throughputHistogram每请求吞吐量分布

系统指标

指标名类型说明
vllm:num_requests_runningGauge正在运行的请求数
vllm:num_requests_waitingGauge等待中的请求数
vllm:num_requests_swappedGauge被 swap 的请求数
vllm:gpu_cache_usage_percGaugeGPU 缓存使用率
vllm:cpu_cache_usage_percGaugeCPU 缓存使用率

批处理指标

指标名类型说明
vllm:avg_prompt_throughput_toks_per_sGauge平均 prompt 处理吞吐量
vllm:avg_generation_throughput_toks_per_sGauge平均生成吞吐量

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_UTILGPU 利用率 (%)
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 部署