news 2026/5/1 19:26:23

8.人工智能实战:大模型服务“看起来正常却突然变慢”?Prometheus + Grafana + GPU 指标构建全链路监控体系

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
8.人工智能实战:大模型服务“看起来正常却突然变慢”?Prometheus + Grafana + GPU 指标构建全链路监控体系

人工智能实战:大模型服务“看起来正常却突然变慢”?Prometheus + Grafana + GPU 指标构建全链路监控体系


一、问题场景:线上最怕的不是报错,而是“偶发性变慢”

在前面的系统优化中,我们已经完成了:

1. FastAPI 封装大模型推理接口 2. vLLM 提升并发吞吐 3. Redis 队列削峰填谷 4. 限流、熔断、降级保护系统 5. 多 GPU 提升推理能力

测试环境压测结果也比较漂亮:

平均延迟:1.2s P95:2.8s 错误率:< 1% GPU 利用率:70% ~ 85%

但真正上线后,业务侧反馈了一个很典型的问题:

“接口大多数时候很快,但偶尔会突然卡一下。” “用户没有看到明确报错,但感觉系统不稳定。” “日志里没有明显异常,但体验就是不好。”

这类问题最难排查。

因为它不是接口完全不可用,也不是服务直接崩溃,而是:

系统局部变慢,但你不知道慢在哪里。

一开始我也犯了一个错误:只去看应用日志。

结果日志里只有:

request success request success request success

看起来全是成功。

但用户体验并不好。

最后排查发现,问题不在接口逻辑,而在:

队列等待时间变长 + 某些请求 token 数过大 + GPU 短时间进入高负载

也就是说,问题发生在“链路中间”,而不是最终错误日志里。

这也是大模型系统和普通 Web 系统最大的区别:

普通接口看错误日志,大模型系统必须看全链路指标。

二、真实问题:只看日志为什么定位不了大模型故障?

很多传统后端系统,排查问题主要看:

1. 应用日志 2. 错误堆栈 3. CPU / 内存 4. 慢 SQL

但大模型推理服务不一样。

一个请求进入系统后,完整链路通常是:

Client ↓ API Gateway ↓ 参数校验 ↓ Redis Queue ↓ Worker ↓ vLLM ↓ GPU ↓ 返回结果

其中任何一层变慢,用户看到的都是:

接口响应慢

但应用日志只会告诉你:

最终成功或失败

它不会告诉你:

1. 请求在队列里等了多久 2. prompt 输入了多少 token 3. 输出生成了多少 token 4. vLLM 推理阶段耗时多少 5. GPU 利用率是否瞬间打满 6. P99 是否已经异常 7. 是否某类长文本请求拖慢了短请求

所以,排查大模型服务问题,不能只看日志,要建立一套可观测体系。


三、原因分析:大模型系统到底要监控什么?

很多人一上来就装 Prometheus、Grafana,然后采一堆指标。

但指标不是越多越好。

真正有用的指标,一定要能回答问题。

大模型服务至少要回答这 5 个问题:

1. 请求有没有变多? 2. 请求有没有变慢? 3. 慢在哪里? 4. GPU 是否成为瓶颈? 5. 队列是否已经积压?

所以我们需要按层设计指标。


四、指标分层设计

1. 接口层指标

接口层负责回答:

服务对用户表现如何?

核心指标:

QPS 成功率 错误率 平均延迟 P95 延迟 P99 延迟

注意,平均延迟只能看趋势,不能代表用户体验。

真正要盯的是:

P95 / P99

因为大模型服务经常出现:

平均值很好看,P99 已经爆炸

2. 请求内容指标

大模型请求不是普通 JSON 请求。

它的成本和以下因素强相关:

prompt 长度 input tokens max_tokens output tokens

同样是一次请求:

20 token 输入 + 64 token 输出

和:

2000 token 输入 + 512 token 输出

消耗完全不同。

所以必须记录:

输入 token 数 输出 token 数 总 token 数

3. 队列层指标

如果系统加了 Redis 队列,必须监控:

队列长度 任务等待时间 任务执行时间 任务失败数

队列长度非常关键。

因为它是系统过载最早出现的信号之一。

如果你只看接口响应时间,通常已经晚了。


4. 模型推理层指标

推理层需要关注:

模型调用耗时 生成速度 tokens/s 超时次数 失败次数

尤其是:

tokens/s

它比单纯的请求耗时更能反映模型真实性能。


5. GPU 层指标

GPU 层至少要监控:

GPU 利用率 显存使用量 显存使用比例 GPU 温度 GPU Power

但这里有个坑:

GPU 利用率高,不一定代表系统高效; GPU 利用率低,也不一定代表系统空闲。

例如:

队列积压严重,但 Worker 没有正常消费

此时 GPU 利用率可能不高,但用户已经很慢。

所以 GPU 指标必须和队列指标、延迟指标一起看。


五、解决方案:Prometheus + Grafana + 自定义指标

这套方案的目标不是“装一个监控面板”,而是构建一个可以定位问题的系统。

架构如下:

FastAPI / Worker ↓ 暴露 /metrics Prometheus ↓ 采集指标 Grafana ↓ 展示趋势 Alertmanager ↓ 告警

本文先实现核心部分:

1. FastAPI 暴露接口指标 2. Worker 暴露任务指标 3. 采集 GPU 指标 4. Prometheus 抓取 5. Grafana 展示 6. 配置基础告警规则

六、可复现项目结构

llm-monitor-demo/ ├── app.py ├── worker.py ├── metrics.py ├── gpu_metrics.py ├── requirements.txt ├── prometheus.yml └── alert_rules.yml

七、安装依赖

pipinstallfastapi uvicorn prometheus-client redis rq transformers

如果你只是复现监控逻辑,不需要真正加载大模型,可以先用 sleep 模拟推理。


八、定义统一指标 metrics.py

fromprometheus_clientimportCounter,Histogram,Gauge# 请求总数LLM_REQUEST_TOTAL=Counter("llm_request_total","Total LLM requests",["endpoint","status"])# 请求延迟LLM_REQUEST_LATENCY=Histogram("llm_request_latency_seconds","LLM request latency seconds",["endpoint"],buckets=[0.1,0.3,0.5,1,2,3,5,10,20,30])# 输入 tokenLLM_INPUT_TOKENS=Histogram("llm_input_tokens","Input tokens per request",buckets=[32,64,128,256,512,1024,2048,4096])# 输出 tokenLLM_OUTPUT_TOKENS=Histogram("llm_output_tokens","Output tokens per request",buckets=[32,64,128,256,512,1024])# 队列长度LLM_QUEUE_SIZE=Gauge("llm_queue_size","Current LLM queue size")# GPU 利用率GPU_UTILIZATION=Gauge("gpu_utilization_percent","GPU utilization percent",["gpu_index"])# GPU 显存使用GPU_MEMORY_USED=Gauge("gpu_memory_used_mb","GPU memory used in MB",["gpu_index"])

九、FastAPI 接口埋点 app.py

这里为了可复现,先用time.sleep()模拟模型推理。

真实项目中,把mock_llm()替换成你的 vLLM 或模型调用即可。

importtimeimportrandomfromfastapiimportFastAPI,ResponsefrompydanticimportBaseModel,Fieldfromprometheus_clientimportgenerate_latest,CONTENT_TYPE_LATESTfrommetricsimport(LLM_REQUEST_TOTAL,LLM_REQUEST_LATENCY,LLM_INPUT_TOKENS,LLM_OUTPUT_TOKENS)app=FastAPI(title="LLM Monitor Demo")classChatRequest(BaseModel):prompt:str=Field(...,min_length=1,max_length=4000)max_tokens:int=Field(default=128,ge=1,le=512)defestimate_tokens(text:str)->int:# 简化估算:真实项目建议用 tokenizer 统计returnmax(1,len(text)//2)defmock_llm(prompt:str,max_tokens:int):input_tokens=estimate_tokens(prompt)output_tokens=random.randint(32,max_tokens)# 模拟推理耗时:输入越长、输出越多,耗时越高cost=0.2+input_tokens*0.001+output_tokens*0.01time.sleep(min(cost,5))return{"answer":"这是模拟的大模型回答","input_tokens":input_tokens,"output_tokens":output_tokens}@app.post("/chat")defchat(req:ChatRequest):endpoint="/chat"start=time.time()try:result=mock_llm(req.prompt,req.max_tokens)cost=time.time()-start LLM_REQUEST_TOTAL.labels(endpoint=endpoint,status="success").inc()LLM_REQUEST_LATENCY.labels(endpoint=endpoint).observe(cost)LLM_INPUT_TOKENS.observe(result["input_tokens"])LLM_OUTPUT_TOKENS.observe(result["output_tokens"])return{"answer":result["answer"],"input_tokens":result["input_tokens"],"output_tokens":result["output_tokens"],"cost_seconds":round(cost,3)}exceptExceptionase:LLM_REQUEST_TOTAL.labels(endpoint=endpoint,status="error").inc()raisee@app.get("/metrics")defmetrics():returnResponse(generate_latest(),media_type=CONTENT_TYPE_LATEST)

启动服务:

uvicorn app:app--host0.0.0.0--port8000

访问指标:

curlhttp://127.0.0.1:8000/metrics

可以看到类似指标:

llm_request_total{endpoint="/chat",status="success"} 10 llm_request_latency_seconds_bucket{endpoint="/chat",le="1.0"} 8 llm_input_tokens_bucket{le="512.0"} 10

十、GPU 指标采集 gpu_metrics.py

如果机器有 NVIDIA GPU,可以通过nvidia-smi获取基础指标。

importsubprocessfrommetricsimportGPU_UTILIZATION,GPU_MEMORY_USEDdefcollect_gpu_metrics():cmd=["nvidia-smi","--query-gpu=index,utilization.gpu,memory.used","--format=csv,noheader,nounits"]try:output=subprocess.check_output(cmd).decode("utf-8").strip()exceptException:returnforlineinoutput.splitlines():parts=[x.strip()forxinline.split(",")]iflen(parts)!=3:continuegpu_index,util,memory_used=parts GPU_UTILIZATION.labels(gpu_index=gpu_index).set(float(util))GPU_MEMORY_USED.labels(gpu_index=gpu_index).set(float(memory_used))

接入到 FastAPI 中:

fromgpu_metricsimportcollect_gpu_metrics@app.get("/metrics")defmetrics():collect_gpu_metrics()returnResponse(generate_latest(),media_type=CONTENT_TYPE_LATEST)

注意:

生产环境更推荐使用 NVIDIA DCGM Exporter。 这里用 nvidia-smi 是为了方便复现。

十一、Prometheus 配置 prometheus.yml

global:scrape_interval:5sscrape_configs:-job_name:"llm-service"metrics_path:"/metrics"static_configs:-targets:["host.docker.internal:8000"]

如果 Prometheus 和服务在同一台 Linux 机器上,也可以写:

targets:["127.0.0.1:8000"]

启动 Prometheus:

dockerrun-d\--nameprometheus\-p9090:9090\-v$(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml\prom/prometheus

浏览器打开:

http://127.0.0.1:9090

查询:

llm_request_total

十二、压测生成数据

安装 locust:

pipinstalllocust

编写locustfile.py

fromlocustimportHttpUser,task,betweenimportrandomclassLLMUser(HttpUser):wait_time=between(0.5,2)@taskdefchat(self):prompts=["解释一下Transformer","请用工程师视角解释大模型部署中的KV Cache","写一段关于人工智能系统架构的长文,要求包含性能、稳定性、监控和部署。",]self.client.post("/chat",json={"prompt":random.choice(prompts),"max_tokens":random.choice([64,128,256,512])})

启动压测:

locust-flocustfile.py--host=http://127.0.0.1:8000

十三、核心 PromQL 查询

1. QPS

sum(rate(llm_request_total[1m]))

2. 错误率

sum(rate(llm_request_total{status="error"}[1m])) / sum(rate(llm_request_total[1m]))

3. P95 延迟

histogram_quantile( 0.95, sum(rate(llm_request_latency_seconds_bucket[5m])) by (le) )

4. P99 延迟

histogram_quantile( 0.99, sum(rate(llm_request_latency_seconds_bucket[5m])) by (le) )

5. 输入 token 分布

histogram_quantile( 0.95, sum(rate(llm_input_tokens_bucket[5m])) by (le) )

6. GPU 利用率

gpu_utilization_percent

十四、Grafana 面板设计

一个真正有用的大模型监控面板,至少要包含以下区域:

1. 请求总览 - QPS - 成功率 - 错误率 2. 延迟分布 - Avg - P95 - P99 3. Token 分布 - Input tokens P95 - Output tokens P95 4. 队列状态 - Queue size - Waiting time 5. GPU 状态 - GPU Util - GPU Memory

我建议把下面两个指标放在同一行:

P99 延迟 + Queue Size

因为如果 P99 上升,同时 Queue Size 上升,基本可以判断:

系统开始排队。

如果 P99 上升,但 Queue Size 不上升,可能是:

模型推理本身变慢,或者某类长 token 请求变多。

十五、告警规则 alert_rules.yml

groups:-name:llm-alertsrules:-alert:LLMHighErrorRateexpr:|sum(rate(llm_request_total{status="error"}[1m])) / sum(rate(llm_request_total[1m])) > 0.05for:2mlabels:severity:warningannotations:summary:"LLM error rate is too high"-alert:LLMHighP99Latencyexpr:|histogram_quantile( 0.99, sum(rate(llm_request_latency_seconds_bucket[5m])) by (le) ) > 10for:3mlabels:severity:warningannotations:summary:"LLM P99 latency is too high"-alert:LLMGPUHighMemoryexpr:gpu_memory_used_mb>22000for:2mlabels:severity:warningannotations:summary:"GPU memory usage is high"

Prometheus 加载规则:

rule_files:-"alert_rules.yml"

十六、验证结果:监控如何帮助定位问题?

压测时我刻意构造三类请求:

短 prompt + 少输出 短 prompt + 多输出 长 prompt + 多输出

从 Grafana 可以观察到:

1. QPS 没有明显变化 2. P99 延迟突然升高 3. Input tokens P95 同步升高 4. GPU 显存缓慢上升

这说明问题不是流量变大,而是:

请求结构变化导致推理成本上升。

如果只看接口日志,你看到的是:

请求成功 请求成功 请求成功

但通过指标可以明确定位:

长文本请求比例变高 → KV Cache 压力变大 → P99 上升

这就是监控系统的价值。


十七、踩坑记录

坑 1:只看平均延迟

平均延迟最容易骗人。

例如:

90% 请求耗时 1s 10% 请求耗时 20s

平均值看起来可能还能接受,但 P99 已经非常差。

所以大模型服务必须看:

P95 / P99

坑 2:只监控 GPU,不监控队列

GPU 利用率低,不代表系统没问题。

如果 Worker 挂了,队列不断堆积,GPU 可能很空,但用户请求已经无法处理。

所以必须同时看:

Queue Size + GPU Util + P99

坑 3:指标命名混乱

一开始我把指标写成:

request_count latency token

后来接入多个服务后完全乱掉。

建议统一前缀:

llm_request_total llm_request_latency_seconds llm_input_tokens llm_output_tokens

坑 4:高频调用 nvidia-smi

nvidia-smi本身有开销,不建议高频执行。

测试环境可以 5 秒采集一次。

生产环境建议:

NVIDIA DCGM Exporter

坑 5:没有给指标加 label

例如同一个系统里有多个模型:

qwen llama deepseek

最好给指标加:

model_name route status

否则后面无法区分到底是哪一个模型慢。


十八、适合收藏的监控 Checklist

接口层: [ ] QPS [ ] 成功率 [ ] 错误率 [ ] P95 延迟 [ ] P99 延迟 请求层: [ ] input tokens [ ] output tokens [ ] max_tokens [ ] prompt length 队列层: [ ] queue size [ ] waiting time [ ] task success [ ] task failed 模型层: [ ] model latency [ ] tokens/s [ ] timeout count GPU层: [ ] GPU utilization [ ] GPU memory used [ ] GPU memory ratio [ ] GPU temperature

十九、经验总结

这次问题给我的最大经验是:

大模型系统不是写完接口就结束,而是必须具备可观测能力。

普通 Web 系统慢了,可能查日志、查 SQL 就能定位。

但大模型服务慢了,问题可能在:

token 分布 队列等待 KV Cache GPU 显存 推理调度

如果没有指标,你只能猜。

而线上系统最怕的就是:

靠猜排查问题。

二十、优化建议

后续可以继续增强:

1. 使用 DCGM Exporter 采集 GPU 指标 2. 接入 Alertmanager 做自动告警 3. 增加 OpenTelemetry Trace 4. 对不同模型增加 model_name 标签 5. 将队列等待时间单独统计 6. 按 token 区间统计不同请求成本 7. 监控 tokens/s 作为模型吞吐指标

一句话总结:

没有监控的大模型系统,就像没有仪表盘的飞机。 能飞,但你不知道什么时候会出事。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 19:19:31

5步掌握TestDisk与PhotoRec:从数据灾难到完整恢复的实战指南

5步掌握TestDisk与PhotoRec&#xff1a;从数据灾难到完整恢复的实战指南 【免费下载链接】testdisk TestDisk & PhotoRec 项目地址: https://gitcode.com/gh_mirrors/te/testdisk 数据丢失是每个计算机用户都可能遇到的噩梦场景&#xff0c;无论是误删除重要文件、分…

作者头像 李华
网站建设 2026/5/1 19:18:35

思源宋体TTF版本兼容性与升级指南

思源宋体TTF版本兼容性与升级指南 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 版本兼容性矩阵 版本发布日期主要特性兼容性说明升级建议v1.0012021-10-15初始版本发布完全兼容所有…

作者头像 李华
网站建设 2026/5/1 19:14:48

【紧急预警】大模型上线前必做的3项R统计审查:Feldman–Hajek偏差指数、Wasserstein公平距离、Bootstrap置信带校验

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;R语言在大语言模型偏见检测中的统计方法导论 在大语言模型&#xff08;LLM&#xff09;部署日益广泛的背景下&#xff0c;系统性偏见可能通过训练数据、词嵌入或生成逻辑被隐式放大。R语言凭借其强大的…

作者头像 李华