vLLM 生产环境指标(/metrics)完全指南:监控模型推理服务的健康与性能
本指南以 vLLM 官方文档 Production Metrics 为核心脉络,系统讲解如何通过 OpenAI 兼容 API 服务器的 /metrics 端点采集指标,并逐一解读调度状态、缓存命中、延迟直方图、投机解码(Speculative Decoding)、NIXL KV Connector 传输以及 MFU 性能等全部指标类型。读完本文,你将掌握指标暴露方式、Prometheus/PromQL 查询配方、各指标对应的底层实现位置,以及指标弃用与隐藏版本间的迁移策略。
指标从哪来:/metrics 端点与示例输出
vLLM 通过 OpenAI 兼容 API 服务器上的 /metrics 端点对外暴露 Prometheus 格式指标,可用于监控系统的健康状态与吞吐性能。启动服务后即可直接抓取:
vllm serve unsloth/Llama-3.2-1B-Instruct
服务启动后,用 curl 即可拉取当前快照:
$ curl http://0.0.0.0:8000/metrics
# HELP vllm:iteration_tokens_total Histogram of number of tokens per engine_step.
# TYPE vllm:iteration_tokens_total histogram
vllm:iteration_tokens_total_sum{model_name="unsloth/Llama-3.2-1B-Instruct"} 0.0
vllm:iteration_tokens_total_bucket{le="1.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
vllm:iteration_tokens_total_bucket{le="8.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
vllm:iteration_tokens_total_bucket{le="16.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
vllm:iteration_tokens_total_bucket{le="32.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
vllm:iteration_tokens_total_bucket{le="64.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
vllm:iteration_tokens_total_bucket{le="128.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
vllm:iteration_tokens_total_bucket{le="256.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
vllm:iteration_tokens_total_bucket{le="512.0",model_name="unsloth/Llama-3.2-1B-Instruct"} 3.0
...
从源码层面看,该端点在 vLLM 的 serve 应用初始化时通过 Prometheus ASGI 中间件挂载:vllm/entrypoints/serve/instrumentator/metrics.py 中 Instrumentator 被创建(绕过默认端点),随后 Mount("/metrics", make_asgi_app(registry=registry)) 把 /metrics 路由到 Prometheus 默认注册表(并对 307 重定向做了规避),因此响应采用标准的 Prometheus text exposition format——# HELP 说明指标含义,# TYPE 标明 gauge/counter/histogram,直方图则以 _sum、_bucket{le="..."}、_count 三组序列呈现。
若使用 Docker 部署,请参考 Docker 部署文档 中的端口映射方式,确保 8000 端口可访问。
指标命名与标签维度:model_name 与 engine
vLLM 所有指标统一使用 vllm: 前缀命名,且默认携带两个标签(见 vllm/v1/metrics/loggers.py 中的 labelnames = ["model_name", "engine"]):
model_name:取VllmConfig.model_config.served_model_name,即服务对外发布的模型名;engine:EngineCore 编号(从0开始)。数据并行(DP)或多 API server 场景下,每个引擎拥有各自独立的标签值序列。
抓取后推荐直接交给 Prometheus 保存,配合 Grafana 仪表盘进行时序聚合。仓库的 examples/observability/dashboards 目录中提供了现成的仪表盘定义,examples/observability/metrics/metrics.py 也给出了客户端采集的示例。
通用指标(General Metrics)
下表覆盖 API 服务器默认暴露的全部通用指标(个别指标仅在特定开关下出现,已单独标注)。指标清单由文档构建脚本 docs/mkdocs/gen_files/generate_metrics.py 通过 AST 扫描 vllm/v1/metrics/loggers.py 中 _gauge_cls/_counter_cls/_histogram_cls 的调用自动提取、自动填回 docs/usage/metrics.md 的 gen:metrics-general 标记处——因此上表与源码永远保持一致,新增指标无需手写文档。
调度器状态(Gauge)
| 指标名 | 类型 | 说明 |
|---|---|---|
vllm:num_requests_running |
Gauge | 正在模型执行批次中的请求数 |
vllm:num_requests_waiting |
Gauge | 等待被处理的请求数 |
vllm:num_requests_waiting_by_reason |
Gauge | 按原因拆分的等待请求数,reason 标签取值 capacity(等待调度容量)或 deferred(被 LoRA 预算、KV transfer、阻塞状态等瞬时约束推迟);所有原因之和等于 vllm:num_requests_waiting |
vllm:engine_sleep_state |
Gauge | 引擎睡眠状态,sleep_state 标签取值 awake/weights_offloaded/discard_all,值为 1 表示处于该状态 |
vllm:kv_cache_usage_perc |
Gauge | KV cache 使用率,1 表示 100% 已用 |
vllm:cache_config_info |
Info | CacheConfig 信息(以恒为 1 的 gauge 模拟 Info 类型,多进程模式下 Prometheus 不直接支持 Info) |
缓存命中计数(Counter)
| 指标名 | 类型 | 说明 |
|---|---|---|
vllm:prefix_cache_queries |
Counter | Prefix Cache 查询量,以被查询的 token 数计 |
vllm:prefix_cache_hits |
Counter | Prefix Cache 命中量,以命中的缓存 token 数计 |
vllm:external_prefix_cache_queries |
Counter | 外部 Prefix Cache(KV Connector 跨实例缓存共享)查询量,以 token 计 |
vllm:external_prefix_cache_hits |
Counter | 外部 Prefix Cache 命中量,以 token 计 |
vllm:mm_cache_queries |
Counter | 多模态缓存查询量,以查询条目数计 |
vllm:mm_cache_hits |
Counter | 多模态缓存命中量,以命中条目数计 |
vllm:corrupted_requests |
Counter | logits 中出现 NaN 的损坏请求累计数(仅当设置环境变量 VLLM_COMPUTE_NANS_IN_LOGITS 时暴露) |
Token 与请求计数(Counter)
| 指标名 | 类型 | 说明 |
|---|---|---|
vllm:num_preemptions |
Counter | 引擎发生的抢占累计次数 |
vllm:prompt_tokens |
Counter | 已处理的 prefill token 总数 |
vllm:prompt_tokens_by_source |
Counter | 按来源拆分的 prompt token 数,source 标签取自 PromptTokenStats.ALL_SOURCES |
vllm:prompt_tokens_cached |
Counter | 缓存命中的 prompt token 数(本地 + 外部) |
vllm:generation_tokens |
Counter | 已处理的 generation token 总数 |
vllm:request_success |
Counter | 成功处理完成的请求数,finished_reason 标签区分结束原因(FinishReason 枚举) |
请求级分布(Histogram)
| 指标名 | 类型 | 说明 |
|---|---|---|
vllm:request_prompt_tokens |
Histogram | 每条请求处理的 prefill token 数分布 |
vllm:request_generation_tokens |
Histogram | 每条请求处理的 generation token 数分布 |
vllm:iteration_tokens_total |
Histogram | 每次 engine step 处理的 token 数分布(bucket 为 1 到 16384 的 2 倍递增序列) |
vllm:request_max_num_generation_tokens |
Histogram | 请求请求的最大生成 token 数分布 |
vllm:request_params_n |
Histogram | n(每次请求生成的序列数)参数分布 |
vllm:request_params_max_tokens |
Histogram | max_tokens 请求参数分布 |
vllm:request_prefill_kv_computed_tokens |
Histogram | prefill 期间新计算的 KV token 数(不含缓存 token)分布 |
vllm:request_num_preemptions |
Histogram | 每条请求被抢占次数的分布 |
其中 request_prompt_tokens、request_generation_tokens、request_max_num_generation_tokens、request_params_max_tokens 与 request_prefill_kv_computed_tokens 的 bucket 由 build_1_2_5_buckets(max_model_len) 生成(即按 1、2、5、10、20、50… 以 model_config.max_model_len 为上限的十进制 mantissa 递增,见 loggers.py 底部的 build_buckets 实现)。
时延分布(Histogram)
| 指标名 | 类型 | 说明 |
|---|---|---|
vllm:time_to_first_token_seconds |
Histogram | 首 token 时延(TTFT)分布,单位秒 |
vllm:inter_token_latency_seconds |
Histogram | token 间时延(ITL)分布,单位秒 |
vllm:request_time_per_output_token_seconds |
Histogram | 每条请求每输出 token 的平均耗时分布 |
vllm:e2e_request_latency_seconds |
Histogram | 端到端请求时延分布,单位秒 |
vllm:request_queue_time_seconds |
Histogram | 请求处于 WAITING 阶段的排队时长分布 |
vllm:request_inference_time_seconds |
Histogram | 请求处于 RUNNING 阶段的推理时长分布 |
vllm:request_prefill_time_seconds |
Histogram | 请求处于 PREFILL 阶段的耗时分布 |
vllm:request_decode_time_seconds |
Histogram | 请求处于 DECODE 阶段的耗时分布 |
时延类直方图共用一套宽桶设计(从 0.3s 到 7680s 的非均匀递增桶),便于在单个序列上观察跨数量级的延迟分布。
KV Cache 驻留时长指标(可选 Histogram)
这三项指标由 PrometheusStatLogger 在 vllm_config.observability_config.kv_cache_metrics 为真时创建,可通过 --kv-cache-metrics 开关启用。由于逐块统计开销大,采用采样上报,采样率由 --kv-cache-metrics-sample 控制(默认 0.01,即约 1% 的块,取值区间 (0, 1],定义见 vllm/config/observability.py)。启用该选项要求日志统计保持开启(即未设置 --disable-log-stats)。
| 指标名 | 类型 | 说明 |
|---|---|---|
vllm:kv_block_lifetime_seconds |
Histogram | KV cache 块从分配到被逐出的生命周期时长分布 |
vllm:kv_block_idle_before_evict_seconds |
Histogram | KV cache 块被逐出前的空闲时长分布 |
vllm:kv_block_reuse_gap_seconds |
Histogram | 同一 KV cache 块两次连续访问之间的时间间隔分布(仅记录最近访问,环形缓冲) |
这三项指标对分析「缓存块被复用前闲置多久」「逐出时块龄多大」非常关键,是评估长上下文与自动前缀缓存收益的重要输入。其数据来源是调度器产出的 kv_cache_eviction_events,在 record() 中逐事件 observe(见 loggers.py 第 1163-1175 行)。
LoRA 信息指标(可选 Gauge)
当检测到 lora_config(即启用 LoRA)时,会额外创建:
| 指标名 | 类型 | 说明 |
|---|---|---|
vllm:lora_requests_info |
Gauge | LoRA 请求运行态信息,标签 max_lora(最大并发 adapter 数)、waiting_lora_adapters、running_lora_adapters |
注意:源码中有一处明确警告——在多引擎数据并行部署下该指标可能不准确/产生误导,应谨慎解读。
推荐的关键查询配方
结合上文指标,常用 PromQL 示例:
- 当前 KV cache 使用率:
vllm:kv_cache_usage_perc - 平均首 token 时延(P99 用
histogram_quantile(0.99, ...)):histogram_quantile(0.99, sum(rate(vllm:time_to_first_token_seconds_bucket[5m])) by (le)) - Prefix Cache 命中率:
vllm:prefix_cache_hits / vllm:prefix_cache_queries - 吞吐量:
rate(vllm:generation_tokens[1m])与rate(vllm:prompt_tokens[1m])
投机解码指标(Speculative Decoding Metrics)
启用投机解码后,服务器会暴露一组 vllm:spec_decode_* 计数器。它们定义于 vllm/v1/spec_decode/metrics.py 的 SpecDecodingProm 中,仅在 speculative_config 存在时才会注册。
| 指标名 | 类型 | 说明 |
|---|---|---|
vllm:spec_decode_num_drafts |
Counter | 投机解码的 draft 轮次数 |
vllm:spec_decode_num_draft_tokens |
Counter | draft token 总数 |
vllm:spec_decode_num_accepted_tokens |
Counter | 被接受的 token 总数 |
vllm:spec_decode_num_accepted_tokens_per_pos |
Counter | 按 draft 位置统计的接受 token 数,position 标签取值 0..num_spec_tokens-1(num_spec_tokens 由 SpeculativeConfig.num_speculative_tokens 决定) |
类注释中给出了三个官方推荐的 PromQL 配方,可直接套用:
-
接受率(acceptance rate):
rate(vllm:spec_decode_num_accepted_tokens_total[$interval]) / rate(vllm:spec_decode_num_draft_tokens_total[$interval]) -
平均接受长度(含 bonus token 的惯例口径):
1 + (rate(vllm:spec_decode_num_accepted_tokens_total[$interval]) / rate(vllm:spec_decode_num_drafts_total[$interval])) -
逐位置接受率向量:
rate(vllm:spec_decode_num_accepted_tokens_per_pos_total[$interval]) / rate(vllm:spec_decode_num_drafts_total[$interval])
此外,对 diffusion 模型(dLLM),vLLM 复用同一套计数器但以 diffusion 语义的名称暴露(vllm:diffusion_num_denoising_steps、vllm:diffusion_num_canvas_positions、vllm:diffusion_num_committed_tokens),此时不注册逐位置序列。若需要在单条请求的响应体中查看投机接受情况,可使用 --per-request-spec-decode-metrics(取值 none/summary/detailed),它是对应聚合 Prometheus 指标的请求级投影。相关特性总览见 docs/features/speculative_decoding 目录。
NIXL KV Connector 指标
启用跨实例 KV 传输(NIXL KV Connector)后,会额外暴露一组传输链路指标,定义于 vllm/distributed/kv_transfer/kv_connector/v1/nixl/stats.py 的 NixlPromMetrics:
| 指标名 | 类型 | 说明 |
|---|---|---|
vllm:nixl_xfer_time_seconds |
Histogram | NIXL KV cache 传输耗时分布(bucket 从 5ms 到 5s) |
vllm:nixl_post_time_seconds |
Histogram | NIXL KV cache 传输后处理(post)耗时分布 |
vllm:nixl_bytes_transferred |
Histogram | 每次传输的字节数分布(2KB 到 16GB 的对数区间) |
vllm:nixl_num_descriptors |
Histogram | 每次传输的 descriptor 数量分布 |
vllm:nixl_num_failed_transfers |
Counter | 失败的 NIXL KV cache 传输次数 |
vllm:nixl_num_failed_notifications |
Counter | 失败的 NIXL 通知次数 |
vllm:nixl_num_kv_expired_reqs |
Counter | KV 过期的请求数。注意:该指标在 P 实例(Prefill 实例)上统计 |
其中 4 个直方图分别对应统计对象中的 transfer_duration、post_duration、bytes_transferred、num_descriptors 数据列,计数器则对应 num_failed_transfers、num_failed_notifications、num_kv_expired_reqs(见 NixlPromMetrics.observe() 的实现)。在跨节点 KV 共享(预填充与解码分离等场景)下,这套指标直接反映了传输带宽瓶颈、失败率与 KV 生命周期管理质量。
模型浮点利用率(MFU)性能指标
MFU 相关指标用于估算硬件算力与显存带宽的实际利用程度,默认关闭,需通过 --enable-mfu-metrics 启动参数显式开启(对应 ObservabilityConfig.enable_mfu_metrics)。定义位于 vllm/v1/metrics/perf.py 的 PerfMetricsProm:
| 指标名 | 类型 | 说明 |
|---|---|---|
vllm:estimated_flops_per_gpu_total |
Counter | 估算的每 GPU 浮点运算次数(供 MFU 计算使用) |
vllm:estimated_read_bytes_per_gpu_total |
Counter | 估算的每 GPU 从内存读取的字节数 |
vllm:estimated_write_bytes_per_gpu_total |
Counter | 估算的每 GPU 向内存写入的字节数 |
三个计数器均为累计值,官方注释给出了换算公式:
-
平均 TFLOPS/GPU:
rate(vllm:estimated_flops_per_gpu_total[1m]) / 1e12 -
平均显存带宽 GB/s/GPU:
(rate(vllm:estimated_read_bytes_per_gpu_total[1m]) + rate(vllm:estimated_write_bytes_per_gpu_total[1m])) / 1e9
将 TFLOPS 除以硬件的理论峰值即可得到 MFU。此外,PerfMetricsLogging 会在引擎日志中周期输出一行类似 MFU: xx.x TF/s/GPU xx.x GB/s/GPU 的聚合统计(见 perf.py 的 log()),无需外部采集也能快速评估。需要注意:多引擎数据并行下日志端不会跨引擎加总每 GPU 性能数字(AggregatedLoggingStatLogger._enable_perf_stats() 返回 False),以免产生误导性的平均值;Prometheus 侧则仍按 engine 标签分别记录。
指标背后的实现与扩展机制
理解源码结构有助于你定位指标语义、排查数据异常或接入自研监控:
- 指标生命周期入口:
StatLoggerManager统一管理统计日志器,AsyncLLM只需对record()/log()两个接口调用即可完成记录与周期性落盘/导出(StatLoggerManager的类注释中明确:日志发生在 EngineCore(每个 scheduler)层级,DP 时每个 EngineCore 各一份;Prometheus 侧则是「单 logger + N 个 label」)。其实现位于 vllm/v1/metrics/loggers.py。 - 两类默认 logger:
LoggingStatLogger把统计写到标准输出(空闲时自动降级为 debug 级,避免生产噪音;内容包含平均 prompt/generation 吞吐、Running/Waiting 请求数、GPU KV cache 使用率、Prefix cache 命中率、抢占数等);PrometheusStatLogger负责注册并写入上文全部 Prometheus 指标。二者通过StatLoggerBase抽象接口解耦。 - 自定义统计插件:
StatLoggerBase是公开的扩展点。社区可在vllm.plugins.STAT_LOGGER_PLUGINS_GROUP入口组注册StatLoggerBase子类,由load_stat_logger_plugin_factories()加载并注入管理器。因此除日志与 Prometheus 外,你可以把同一份SchedulerStats/IterationStats转发到自研监控系统。 - 多引擎聚合:
AggregatedLoggingStatLogger会把多个引擎的 running/waiting 请求数与 KV cache 使用率在日志端聚合后输出(前缀为N Engines Aggregated),PerEngineStatLoggerAdapter则按引擎各自生成独立 logger。Prometheus 路径默认使用multiprocess_mode="mostrecent"的 gauge,以避免多 worker 场景重复计数(见各 gauge 创建参数)。 - 信息类指标:
cache_config_info通过log_metrics_info()在每个引擎初始化时写入恒为 1 的 gauge,把 KV block 大小等 CacheConfig 元数据以标签形式暴露,便于告警规则按配置维度过滤。
观测行为相关的其他开关
vllm/config/observability.py 中还定义了与指标采集行为相关的若干开关,可根据监控需求组合使用:
--kv-cache-metrics:开启 KV cache 驻留时长直方图(前文 3 项指标),配合--kv-cache-metrics-sample(默认 0.01)控制采样率以控制开销;--enable-mfu-metrics:开启 MFU 三类计数器;--enable-logging-iteration-details:在 EngineCore 日志中输出每个迭代的 context/generation 请求数、token 数与耗时等细节(对应LoggingStatLogger._log_iteration_details()的实现);--cudagraph-metrics:开启 CUDA graph 相关统计(padded/unpadded token 数、dispatch 模式及观测频次)。
指标弃用与隐藏策略
为保证兼容性平滑过渡,vLLM 对指标的弃用采用「三段式」节奏(即原文档的 Deprecation Policy):
- 指标在版本
X.Y被标记弃用(deprecated); - 在
X.Y+1中默认隐藏(不再出现在/metrics输出中),但可通过临时逃生舱参数--show-hidden-metrics-for-version=X.Y重新启用,以便用户迁移告警与仪表盘; - 在
X.Y+2中彻底移除。
该参数的底层逻辑见 vllm/config/observability.py:show_hidden_metrics 属性调用 version._prev_minor_version_was(self.show_hidden_metrics_for_version) 判断目标版本是否属于已过去的小版本,从而决定是否暴露被隐藏的指标;同时该字段会校验合法版本号格式。典型用法:如果某指标在 v0.7.0 起被隐藏,则启动参数追加 --show-hidden-metrics-for-version=0.7,即可作为临时兼容手段继续查询旧指标,但应尽快迁移到替代指标,因为它很可能在后续版本中被删除。因此升级 vLLM 版本后若发现某条告警「哑掉」,应优先怀疑目标指标进入了隐藏窗口,再决定用逃生舱还是迁移新指标。
小结
围绕 docs/usage/metrics.md 及其背后四份源码文件,你可以拿到一套完整的生产监控方案:调度与容量看 Gauge,吞吐与缓存命中看 Counter,TTFT/ITL/端到端时延看 Histogram,投机解码效果与 KV 传输质量各有专属指标集,算力利用则依赖 --enable-mfu-metrics 的计数器配合 PromQL 计算。配合弃用逃生舱机制与插件化 StatLogger,vLLM 的 /metrics 既能支撑日常巡检,也能平滑接入已有 Prometheus + Grafana 监控体系。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python08
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00