对于部署了AI推理服务的团队来说,最头疼的往往不是模型精度不够,而是服务上线后性能表现不稳定:白天请求量大时推理延迟飙升,晚上空闲时GPU又在空转。要解决这类问题,第一件事就是把推理服务的运行状态完整地暴露出来,而不是靠人肉登录服务器敲nvidia-smi。Prometheus和Grafana是目前最成熟的组合,前者负责定时抓取指标并存储,后者负责把这些数据画成直观的图表,再配上告警规则,就能形成一个完整的监控闭环。

一、先让推理服务主动暴露指标
很多推理框架本身不会直接输出Prometheus格式的指标,比如你用TensorRT写了一个ResNet的图像分类服务,代码里可能只有推理函数的耗时打印。这时候有两种做法:一是使用框架自带的监控插件(例如vLLM、Triton Inference Server原生支持Prometheus端点),二是自己动手在推理服务里加一个指标暴露端口。考虑到很多团队用的是自己封装的推理服务,第二种做法更通用。
以Python为例,可以引入prometheus_client库,在服务启动时创建一个HTTP服务专门用于暴露指标。这里的关键不是简单记录每次推理的耗时,而是要区分请求排队时间、模型真正计算时间、输入预处理时间和输出后处理时间。这样才能在延迟异常时快速判断是队列积压还是模型本身变慢。下面给出一段最小化的指标暴露代码,其中使用Gauge记录当前正在处理的请求数,Histogram记录端到端延迟,Counter记录推理总次数和失败次数。
import time
from prometheus_client import start_http_server, Gauge, Histogram, Counter
# 指标定义
in_flight_requests = Gauge('inference_in_flight_requests', '当前正在处理的推理请求数')
inference_latency = Histogram('inference_latency_seconds', '推理端到端延迟', buckets=[0.01, 0.05, 0.1, 0.2, 0.5, 1.0, 2.0, 5.0])
inference_total = Counter('inference_requests_total', '推理请求总数')
inference_errors = Counter('inference_errors_total', '推理失败总数')
start_http_server(8000)
def run_inference(input_data):
in_flight_requests.inc()
start = time.time()
try:
# 实际推理逻辑
result = model(input_data)
inference_total.inc()
return result
except Exception:
inference_errors.inc()
raise
finally:
latency = time.time() - start
inference_latency.observe(latency)
in_flight_requests.dec()
这段代码运行后,访问本机8000端口就能看到Prometheus格式的指标。如果你使用的推理引擎是Triton,那根本不用自己写这些代码,Triton默认在8002端口暴露了非常详细的队列、批处理、GPU显存指标。无论哪种方式,核心思想都是把内部运行状态变成可抓取的数字。
另外要注意,如果你的推理服务运行在容器里,需要把指标端口映射出来,同时保证Prometheus能够通过网络访问到该端口。生产环境中建议将指标端口与推理业务端口分离,避免互相干扰。
二、部署Prometheus并配置抓取任务
Prometheus本身是一个单二进制文件,用Docker运行最方便。下面给出一份docker-compose配置,同时启动Prometheus和Node Exporter(用于采集宿主机CPU、内存、磁盘等基础指标)。Node Exporter不是必须的,但如果你的推理服务跑在裸机上,它能帮你发现主机层面的瓶颈,比如CPU抢占导致推理线程饿死。
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
ports:
- "9090:9090"
restart: unless-stopped
node_exporter:
image: quay.io/prometheus/node-exporter:latest
container_name: node_exporter
ports:
- "9100:9100"
restart: unless-stopped
volumes:
prometheus_data:
接下来是Prometheus的核心配置文件prometheus.yml。这里需要定义两个抓取任务:一个针对Node Exporter,另一个针对你的推理服务。下面的示例假设推理服务运行在宿主机IP为192.168.1.100,指标端口为8000。如果你的推理服务和Prometheus运行在同一个Docker网络中,直接用服务名或者容器IP即可。
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['node_exporter:9100']
- job_name: 'inference'
static_configs:
- targets: ['192.168.1.100:8000']
metrics_path: '/metrics'
保存配置后运行docker compose up -d,然后访问http://localhost:9090/targets,就能看到两个抓取任务的状态。如果状态是UP,说明Prometheus已经在正常收集数据。此时你可以在Graph页面输入inference_latency_seconds_count来验证是否能查到数据。这一步成功之后,监控体系的地基就算打好了。
有些推理服务暴露的指标名称不符合Prometheus命名规范,或者包含一些不必要的高基数标签,可以在scrape_configs里使用metric_relabel_configs对指标做过滤和重命名。比如只保留inference_开头的指标,或者把某个标签drop掉以控制存储压力。
三、用Grafana构建推理监控看板
Grafana负责把Prometheus里的数据变成人看得懂的图表。同样用Docker启动一个Grafana实例,然后添加Prometheus数据源。首次登录Grafana默认账号密码都是admin,登录后强制修改密码。添加数据源时URL填写http://prometheus:9090(如果在同一个docker-compose网络里),保存后就可以开始创建仪表盘了。
针对AI推理服务,建议至少创建以下四类面板:请求量趋势、延迟分位数、GPU显存占用、队列长度。请求量面板可以直接查询inference_requests_total的增长率,延迟面板使用histogram_quantile函数计算P50、P95、P99,GPU显存如果使用Triton则可以直接用nv_gpu_memory_used_bytes,自己实现的推理服务也可以通过NVIDIA的DCGM Exporter采集GPU指标。下面给出一个P95延迟的PromQL表达式示例:
histogram_quantile(0.95, sum(rate(inference_latency_seconds_bucket[5m])) by (le))
这个表达式的含义是计算最近5分钟内所有推理请求延迟的P95值。如果这个值在业务高峰期突然升高,而GPU利用率却很低,那大概率是请求排队导致的,需要调整批处理大小或者增加实例数量。另一个非常实用的面板是in_flight_requests的实时曲线,它能直观反映当前有多少请求正在被处理,如果这个值持续接近你的最大并发数,说明服务已经饱和。
你不需要从零开始画所有面板,Grafana支持导入JSON格式的仪表盘。下面是一个精简的仪表盘JSON片段,包含一个延迟面板和一个请求量面板,把它导入Grafana就能快速看到效果。注意导入前需要先把数据源uid替换成你自己的Prometheus数据源uid。
{
"panels": [
{
"title": "推理延迟P95",
"type": "timeseries",
"targets": [
{
"expr": "histogram_quantile(0.95, sum(rate(inference_latency_seconds_bucket[5m])) by (le))",
"legendFormat": "P95"
}
]
},
{
"title": "请求速率",
"type": "timeseries",
"targets": [
{
"expr": "sum(rate(inference_requests_total[5m]))",
"legendFormat": "QPS"
}
]
}
]
}
完成核心面板后,还可以补充主机级别的CPU、内存指标。Node Exporter暴露的node_cpu_seconds_total配合irate函数可以算出CPU使用率,node_memory_MemAvailable_bytes可以帮助判断是否因为内存不足导致模型被换出到swap。这些指标虽然不直接反映推理性能,但往往是性能问题的诱因。
四、配置告警规则,让问题自动找上门
监控看板只能让人主动查看,真正高效的监控系统应该能在问题发生时立即通知到人。Prometheus自带告警规则评估能力,可以在prometheus.yml同级目录下创建一个alert_rules.yml,然后在Prometheus配置的rule_files字段中引用它。下面给出一条实用的告警规则:推理延迟P95连续5分钟超过1秒就触发告警。
groups:
- name: inference_alerts
interval: 30s
rules:
- alert: HighInferenceLatency
expr: histogram_quantile(0.95, sum(rate(inference_latency_seconds_bucket[5m])) by (le)) > 1
for: 5m
labels:
severity: warning
annotations:
summary: "推理服务延迟过高"
description: "推理延迟P95已超过1秒,当前值 {{ $value }}s"
要让告警真正发送到你的邮箱、钉钉或者企业微信,还需要部署Alertmanager。Alertmanager是Prometheus生态中的一个独立组件,负责接收告警、去重、分组和路由。在docker-compose中增加alertmanager服务,并在Prometheus配置中指定alertmanager地址。下面是一个最小的Alertmanager配置,它把告警发送到Webhook地址,实际使用中你可以把Webhook替换成钉钉机器人或者企业微信机器人。
route:
receiver: 'webhook'
receivers:
- name: 'webhook'
webhook_configs:
- url: 'http://your-webhook-endpoint/alert'
告警规则不宜设置得过于敏感,否则很容易产生告警疲劳。建议先从少数的关键指标开始,比如推理服务不可用、延迟超过阈值、错误率突增。等团队习惯了告警节奏后,再逐步增加GPU温度、显存碎片率等高级指标。另外,告警信息里最好带上具体的服务和实例标签,方便快速定位。
五、监控体系落地后的持续优化
监控系统搭建完成只是第一步,真正的价值在于持续使用和调优。AI推理服务的特点是负载波动大、批处理策略对延迟影响显著。你可以利用Prometheus记录的历史数据,分析一天内不同时段的请求量和延迟分布,从而制定更合理的自动扩缩容策略。例如观察到凌晨2点到6点请求量几乎为零,就可以在这个窗口把推理实例缩减到最小,节省GPU资源成本。
另一个值得投入的方向是自定义指标细分。如果你使用Transformer类模型,可以把prefill时间和decode时间分开记录,因为这两类计算对GPU的消耗模式完全不同。还可以记录请求的输入token数和输出token数,配合延迟指标能算出token吞吐和token延迟,这是评估LLM推理服务质量的核心指标。这些指标的采集方式与前面的示例类似,只需要在推理服务中增加对应的Counter或者Histogram即可。
最后提醒一点,Prometheus默认的数据保留时间是15天,对于需要长期追踪性能趋势的团队,建议接入Thanos或者VictoriaMetrics等长期存储方案。另外,Grafana的告警功能也能作为Alertmanager的补充,如果你不想单独维护Alertmanager,可以直接在Grafana里设置告警规则,通过Grafana的联系点发送通知。不过对于生产环境,独立部署Alertmanager的灵活性和可靠性更高。
整个方案从零开始到能收到告警通知,大约只需要半天时间。核心步骤就是让推理服务暴露指标、配置Prometheus抓取、用Grafana画图、设置Alertmanager告警。这套监控体系不仅适用于AI推理服务,对于任何需要观察性能表现的在线服务都是通用的,只不过推理服务在GPU和批处理指标上需要多花一些心思。开始动手吧,等你看到第一张延迟曲线图时,很多之前摸不着头脑的性能问题会自动浮现出答案。
AI推理PrometheusGrafana修改时间:2026-09-30 19:09:08