10.2 可观测性:Prometheus 指标、Grafana 看板与日志
vLLM v0.26 的 Prometheus 指标体系(请求时延/调度/KV缓存/投机解码)、Grafana 看板、结构化日志与告警设计
可观测性是运维的眼睛。LLM 推理服务与普通 Web 服务最大的不同:瓶颈不在 CPU/内存,而在 GPU 利用率、KV Cache 水位和队列深度。vLLM v0.26 的指标体系围绕这三个维度设计——这一节讲清”看什么指标、怎么看、怎么告警”。
📑 目录
- 1. 指标架构:v0.26 的 Rust 指标引擎
- 2. 核心指标解读(按用途分组)
- 3. Grafana 看板与 PromQL 实战
- 4. 结构化日志与请求追踪
- 5. 告警设计:什么该报警,什么不该
- 📝 总结
- 🎯 自我检验清单
- 📚 参考资料
1. 指标架构:v0.26 的 Rust 指标引擎
1.1 从 Python 到 Rust
v0.26 把指标采集从 Python 迁移到了 Rust 引擎核心(rust/src/metrics),通过 prometheus-client crate 注册。这也是 v0.26 整体”引擎 Rust 化”的一部分(第 4 章的 Tokenizer、第 6 章的调度器同理)。
服务端 /metrics 端点(Prometheus 文本格式,OpenMetrics)
├── RequestMetrics → 请求级时延、token 数(e2e、TTFT、TPOT 等)
├── SchedulerMetrics → 队列、KV 缓存、前缀缓存、抢占
└── ApiServerMetrics → HTTP 层(仍在 Python 侧)
旧 Python 指标(vllm:xxx 命名)→ 迁移中,v0.26 以 vllm: 前缀(冒号)为新命名
📌 关键点:v0.26 指标名采用
vllm:冒号前缀(如vllm:time_to_first_token_seconds),与旧版vllm_time_to_first_token_seconds(下划线)不同——查文档、抄 PromQL 时先确认版本对应的命名。
1.2 开启方式
# serve 时默认开启(--enable-prometheus-metrics 默认 true)
vllm serve meta-llama/Llama-3.1-8B-Instruct --port 8000
# 验证
curl localhost:8000/metrics | head -20
# Prometheus 抓取配置(K8s ServiceMonitor)
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: vllm
spec:
selector: { matchLabels: { app: vllm } }
endpoints:
- port: metrics # 8000/metrics
interval: 15s
scrapeTimeout: 10s
2. 核心指标解读(按用途分组)
2.1 请求时延组(SLO 的直接来源)
| 指标 | 类型 | 含义 |
|---|---|---|
vllm:time_to_first_token_seconds | Histogram | TTFT(首 token 时延)——第 9.1 章 SLO 的两个指标之一 |
vllm:e2e_request_latency_seconds | Histogram | 端到端请求时延 |
vllm:inter_token_latency_seconds | Histogram | ITL(相邻 token 间隔) |
vllm:request_time_per_output_token_seconds | Histogram | 每输出 token 耗时(吞吐的反面) |
vllm:request_queue_time_seconds | Histogram | 排队等待时间(调度压力的直接体现) |
vllm:request_prefill_time_seconds | Histogram | Prefill 阶段耗时 |
vllm:request_decode_time_seconds | Histogram | Decode 阶段耗时 |
2.2 调度与队列组(扩缩容的输入)
| 指标 | 类型 | 含义 |
|---|---|---|
vllm:num_requests_running | Gauge | 正在运行的请求数 |
vllm:num_requests_waiting | Gauge | 等待中的请求数 |
vllm:num_requests_waiting_by_reason | Gauge | 等待原因细分(KV 空间不足?抢占?) |
vllm:num_preemptions | Counter | 累计抢占次数(>0 说明负载已超容) |
2.3 KV 缓存组(容量瓶颈)
| 指标 | 类型 | 含义 |
|---|---|---|
vllm:kv_cache_usage_perc | Gauge | KV 缓存占用比例(0-1)——最重要的容量指标 |
vllm:kv_block_lifetime_seconds | Histogram | KV block 存活时长 |
vllm:kv_block_reuse_gap_seconds | Histogram | block 复用的间隔 |
2.4 前缀缓存组(缓存命中率)
| 指标 | 类型 | 含义 |
|---|---|---|
vllm:prefix_cache_queries | Counter | 前缀缓存查询次数(token 数) |
vllm:prefix_cache_hits | Counter | 命中 token 数 |
vllm:external_prefix_cache_hits/queries | Counter | 外部 KV 连接器(跨实例共享缓存)的命中/查询 |
vllm:prompt_tokens_cached | Counter | 缓存命中的 prompt token 数 |
vllm:prompt_tokens_by_source | Counter | prompt token 来源分布(命中/未命中) |
2.5 吞吐与投机解码组
| 指标 | 类型 | 含义 |
|---|---|---|
vllm:generation_tokens | Counter | 生成 token 总数(算吞吐的分母) |
vllm:prompt_tokens | Counter | prompt token 总数 |
vllm:spec_decode_num_accepted_tokens | Counter | 投机解码接受 token 数 |
vllm:spec_decode_num_draft_tokens | Counter | 草稿 token 数 |
vllm:spec_decode_num_drafts | Counter | 草稿次数 |
2.6 健康组(异常检测)
| 指标 | 类型 | 含义 |
|---|---|---|
vllm:request_success | Counter | 成功请求数(失败率的分母参照) |
vllm:corrupted_requests | Counter | logits 出现 NaN 的请求数(模型出问题的信号) |
📌 关键点:运维只盯 4 个指标就能覆盖 80% 场景:
num_requests_waiting(过载?)、kv_cache_usage_perc(容量?)、time_to_first_token_seconds的 p95(SLO 达标?)、num_preemptions(抢占风暴?)。其余指标是排查时的下钻入口。
3. Grafana 看板与 PromQL 实战
3.1 核心 PromQL 查询
# 1. TTFT 分位数(SLO 达标判断)
histogram_quantile(0.95, sum by (le) (rate(vllm:time_to_first_token_seconds_bucket[5m])))
# 2. 前缀缓存命中率(5 分钟窗口)
rate(vllm:prefix_cache_hits[5m]) / rate(vllm:prefix_cache_queries[5m])
# 3. 过载判定:等待/运行比
vllm:num_requests_waiting / (vllm:num_requests_running + vllm:num_requests_waiting)
# 4. KV 缓存水位
vllm:kv_cache_usage_perc
# 5. 吞吐(token/s)
rate(vllm:generation_tokens[1m])
3.2 看板三件套
| 看板 | 内容 | 用途 |
|---|---|---|
| 总览 | 请求量、TTFT p50/p95、吞吐、队列 | 值班大屏 |
| 容量 | KV 缓存水位、GPU 利用率、等待原因 | 扩容决策 |
| 缓存 | 前缀命中率、spec decode 接受率 | 优化效果验证 |
💡 提示:Production Stack(10.1 第 5 节)自带全套 Grafana 看板(vLLM + LMCache),
grafanaDashboards.enabled: true即开——先用官方看板,再按需定制,不要从零画。
4. 结构化日志与请求追踪
4.1 结构化日志
vLLM 的日志走标准库,生产用 JSON 结构化输出方便采集:
# 环境变量开启(示例,以官方文档为准)
export VLLM_LOGGING_LEVEL=INFO
{"timestamp":"...", "level":"INFO", "msg":"Received request ...", "request_id":"...", "model":"..."}
- 日志采集:Promtail/Fluent Bit → Loki(轻量)或 ELK(重型)
- 日志级别:INFO(默认)/ DEBUG(排障)/ WARNING / ERROR
4.2 请求 ID 贯穿
vLLM 每个请求有唯一 request_id,指标(按 request_id 打点)+ 日志(打印 request_id)配合才能做单请求的时延拆解:
一次慢请求的排查链路:
1. 告警发现 TTFT p95 恶化
2. 日志按 request_id 查该请求的 queue_time / prefill_time / decode_time
3. 指标看同窗口 kv_cache_usage_perc 是否打满 → 定位是容量还是代码问题
📌 关键点:可观测性的终点是”单请求可追踪”。没有 request_id 贯穿,时延恶化只能猜;有了它,10 分钟内能定位到”排队慢 / prefill 慢 / decode 慢 / 重试导致”的哪一环。
5. 告警设计:什么该报警,什么不该
5.1 告警四原则
| 原则 | 说明 | 反例 |
|---|---|---|
| 告警 = 需要人处理的事件 | 可自动恢复的别报警 | 单次 TTFT 超时 |
| 用比率,不用绝对值 | 绝对值随负载波动 | waiting > 100 报警 |
| SLO 先行 | 告警与 SLO 绑定,而非指标绑定 | 指标波动报警 |
| 预留恢复期 | 持续 N 分钟才触发,避免抖动 | 立即报警 |
5.2 vLLM 生产告警清单(推荐起点)
# 1. 容量:KV 缓存打满持续 5 分钟 → 扩容/降负载(P1)
vllm:kv_cache_usage_perc > 0.95
# 2. 过载:等待/运行比 > 2 持续 5 分钟(P1,说明排队失控)
vllm:num_requests_waiting / (vllm:num_requests_running + vllm:num_requests_waiting) > 0.67
# 3. SLO:TTFT p95 超阈值持续 10 分钟(P2)
histogram_quantile(0.95, sum by (le) (rate(vllm:time_to_first_token_seconds_bucket[5m]))) > 2
# 4. 抢占:抢占速率 > 0 持续 5 分钟(P2,容量预警)
rate(vllm:num_preemptions[5m]) > 0
# 5. 健康:corrupted_requests 增长(P1,模型输出异常)
increase(vllm:corrupted_requests[5m]) > 0
5.3 不该报警的
- 单次请求超时:重试即可 → 用错误率(5 分钟窗口 > 1%)代替
- GPU 利用率低:不是故障——可能是前缀缓存命中率高(好事)或负载低
- 前缀命中率下降:先看是否换了请求分布,再决定是否处理
- 副本重启 1 次:K8s 自动恢复 → 关注”重启频率趋势”而非单次
💡 提示:告警的终极检验:报警了,值班同学知道下一步干什么吗? 每条告警配”处理手册”(runbook)——查什么指标、看什么日志、什么操作可缓解。没有 runbook 的告警是噪音。
📝 总结
- v0.26 指标引擎:Rust 化(prometheus-client crate),指标名
vllm:冒号前缀 - 4 个核心指标:
num_requests_waiting、kv_cache_usage_perc、TTFT 分位数、num_preemptions - PromQL 四连:TTFT 分位数、命中率、等待比、吞吐
- 单请求可追踪:request_id 贯穿日志与指标
- 告警四原则:需要人处理、用比率、SLO 先行、预留恢复期
- 每条告警配 runbook,否则是噪音
🎯 自我检验清单
- v0.26 指标名为什么是
vllm:前缀?旧版是什么? - KV 缓存水位用什么指标?怎么在 Grafana 画出来?
- 前缀缓存命中率的 PromQL 怎么写?
- 判断”过载”用哪两个指标的组合?
- 单请求慢,怎么用 request_id 拆解时延?
- 什么场景应该报警,什么场景不该报?
- corrupted_requests 指标的含义?
📚 参考资料
- vLLM 官方文档:Production Metrics(指标完整清单)(https://docs.vllm.ai/en/latest/usage/metrics.html)
- vLLM 设计文档:Metrics(指标设计决策)(https://docs.vllm.ai/en/stable/design/metrics.html)
- Prometheus 官方文档(https://prometheus.io/docs/)
- Grafana 官方文档(https://grafana.com/docs/)