GTE-large部署教程:Prometheus+Grafana监控GPU利用率与API响应延迟
1. 为什么需要监控这个模型服务
你刚把 GTE-large 文本向量模型跑起来了,网页能打开、API 能调通、NER 和情感分析结果也看着挺准——但接下来呢?
如果它突然变慢了,你第一时间知道吗?
如果 GPU 显存悄悄涨到 98%,而你还在等一个 30 秒没返回的/predict请求,问题出在哪?
如果用户反馈“问答功能时好时坏”,你是重启服务,还是翻日志查了 20 分钟才发现是某次批量请求把显存打满了?
这不是理论问题。真实场景中,一个没被监控的 AI 服务,就像一辆没装仪表盘的车——能开,但不知道油还剩多少、发动机温度是否异常、刹车响应是否延迟。
本文不讲怎么训练 GTE-large,也不重复 ModelScope 模型下载步骤。我们聚焦一个工程落地中最容易被跳过的环节:让这个基于 Flask 的多任务 Web 应用,真正“可观察”(observable)。
你会亲手完成三件事:
把 Prometheus 嵌入 Flask 应用,自动采集 GPU 利用率、显存占用、API 响应时间、请求成功率;
用 Grafana 搭建专属监控看板,一眼看清“哪个任务最耗 GPU”、“哪类请求延迟最高”;
避开常见坑:Flask 多进程下指标冲突、GPU 指标采集权限问题、Grafana 面板数据断连。
全程基于你已有的项目结构(/root/build/),不新增模型、不重写业务逻辑,只加监控能力。
2. 环境准备与监控组件安装
2.1 确认基础依赖已就位
你的项目已在运行,说明以下组件已安装:
- Python 3.8+
flask,torch,transformers,modelscope- NVIDIA 驱动 +
nvidia-smi可用(验证命令:nvidia-smi -L)
注意:若
nvidia-smi报错或无输出,请先在宿主机安装驱动和 CUDA 工具包。容器环境需确保以--gpus all启动,并挂载/dev/nvidia*设备。
2.2 安装监控核心组件
在/root/build/目录下执行:
pip install prometheus-client psutil nvidia-ml-py3prometheus-client: 提供 Flask 中间件和指标注册能力;psutil: 获取进程级 CPU/内存信息(辅助诊断);nvidia-ml-py3: 官方 Python 封装,安全读取 GPU 状态(比解析nvidia-smi输出更稳定)。
验证安装:运行
python -c "import pynvml; pynvml.nvmlInit(); print('OK')",无报错即成功。
2.3 修改启动脚本,启用监控端点
编辑/root/build/start.sh,将原启动命令:
python app.py替换为:
# 启用 Prometheus 指标暴露端口 9090(与 Flask 的 5000 端口分离) python app.py --monitor-port 9090并在app.py开头添加参数解析支持(插入在import之后、if __name__ == "__main__":之前):
import argparse import sys parser = argparse.ArgumentParser() parser.add_argument("--monitor-port", type=int, default=9090, help="Port for Prometheus metrics") args = parser.parse_args()同时,将 Flask 启动行改为:
if __name__ == "__main__": app.run(host='0.0.0.0', port=5000, debug=False) # 生产环境必须关 debug关键点:监控端口(9090)与业务端口(5000)严格分离。避免 Prometheus 抓取器干扰业务流量,也防止业务异常导致监控失联。
3. 在 Flask 应用中嵌入监控指标
3.1 注册核心指标对象
在app.py顶部import区块后,添加:
from prometheus_client import Counter, Histogram, Gauge, make_wsgi_app from werkzeug.middleware.dispatcher import DispatcherMiddleware import threading import time import pynvml # 初始化 NVML(仅需一次) pynvml.nvmlInit() # 1. 请求计数器:按 task_type 和 HTTP 状态码维度 REQUEST_COUNT = Counter( 'gte_api_requests_total', 'Total HTTP Requests', ['task_type', 'status_code'] ) # 2. 响应延迟直方图:按 task_type 统计 P90/P95 延迟 REQUEST_DURATION = Histogram( 'gte_api_request_duration_seconds', 'API Request Duration', ['task_type'], buckets=(0.1, 0.25, 0.5, 1.0, 2.0, 5.0, 10.0) ) # 3. GPU 指标:单卡场景下使用 device 0 GPU_UTILIZATION = Gauge('gpu_utilization_percent', 'GPU Utilization %', ['device']) GPU_MEMORY_USED = Gauge('gpu_memory_used_bytes', 'GPU Memory Used Bytes', ['device']) GPU_MEMORY_TOTAL = Gauge('gpu_memory_total_bytes', 'GPU Memory Total Bytes', ['device']) # 4. 进程指标(可选,辅助定位 OOM) PROCESS_MEMORY = Gauge('process_memory_bytes', 'Flask Process Memory Usage')3.2 添加请求中间件,自动记录请求指标
在app.py中,在@app.route('/predict', methods=['POST'])路由函数上方,插入如下装饰器函数(推荐放在app实例创建后、路由定义前):
@app.before_request def before_request(): # 记录请求开始时间 request.start_time = time.time() @app.after_request def after_request(response): # 获取 task_type(从 request.json 或默认值) task_type = "unknown" try: if request.endpoint == 'predict' and request.method == 'POST': data = request.get_json() task_type = data.get("task_type", "unknown") if data else "unknown" except: pass # 计算耗时并记录 duration = time.time() - request.start_time REQUEST_DURATION.labels(task_type=task_type).observe(duration) # 记录状态码 REQUEST_COUNT.labels(task_type=task_type, status_code=response.status_code).inc() return response3.3 启动 GPU 指标采集线程(后台常驻)
在app.py底部if __name__ == "__main__":块内,在app.run(...)之前,添加:
def collect_gpu_metrics(): """每 3 秒采集一次 GPU 指标""" handle = pynvml.nvmlDeviceGetHandleByIndex(0) # 假设单卡 while True: try: util = pynvml.nvmlDeviceGetUtilizationRates(handle) mem_info = pynvml.nvmlDeviceGetMemoryInfo(handle) GPU_UTILIZATION.labels(device='0').set(util.gpu) GPU_MEMORY_USED.labels(device='0').set(mem_info.used) GPU_MEMORY_TOTAL.labels(device='0').set(mem_info.total) except Exception as e: # 忽略临时错误,避免线程崩溃 pass time.sleep(3) # 启动采集线程(守护线程,随主进程退出) threading.Thread(target=collect_gpu_metrics, daemon=True).start()3.4 暴露 Prometheus 指标端点
在app.py中,在所有路由定义之后、if __name__ == "__main__":之前,添加:
# 创建 /metrics 子应用 metrics_app = make_wsgi_app() # 将 metrics_app 挂载到主 Flask 应用 app.wsgi_app = DispatcherMiddleware(app.wsgi_app, { '/metrics': metrics_app })此时访问
http://<your-ip>:9090/metrics即可看到原始指标文本,包含gte_api_requests_total、gte_api_request_duration_seconds_bucket、gpu_utilization_percent等。
4. 部署 Prometheus 与 Grafana
4.1 一键启动 Prometheus(Docker 方式)
在服务器上执行(无需 root):
mkdir -p /root/prometheus && cd /root/prometheus cat > prometheus.yml << 'EOF' global: scrape_interval: 10s scrape_configs: - job_name: 'gte-api' static_configs: - targets: ['host.docker.internal:9090'] # 若 Prometheus 在容器中运行,指向宿主机 # 若 Prometheus 与 Flask 同在宿主机,改为 targets: ['localhost:9090'] EOF docker run -d \ --name prometheus \ -p 9090:9090 \ -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \ -v $(pwd)/data:/prometheus \ --restart=always \ prom/prometheus:latest \ --config.file=/etc/prometheus/prometheus.yml \ --storage.tsdb.path=/prometheus \ --web.console.libraries=/usr/share/prometheus/console_libraries \ --web.console.templates=/usr/share/prometheus/consoles验证:浏览器打开
http://<your-ip>:9090/targets,状态应为 UP;http://<your-ip>:9090/graph输入gte_api_requests_total应有数据。
4.2 一键启动 Grafana(Docker 方式)
docker run -d \ --name grafana \ -p 3000:3000 \ -v grafana-storage:/var/lib/grafana \ --restart=always \ -e "GF_SECURITY_ADMIN_PASSWORD=admin" \ grafana/grafana-oss:latest首次登录:
http://<your-ip>:3000,账号admin/ 密码admin→ 登录后强制修改密码。
4.3 在 Grafana 中配置数据源与看板
添加 Prometheus 数据源
Settings → Data Sources → Add data source → Prometheus → URL 填http://<your-ip>:9090→ Save & test。导入预置看板(推荐)
Dashboard → Import → 输入以下 JSON(复制粘贴),Name 填 “GTE-large Service Monitor”:
{ "dashboard": { "panels": [ { "title": "GPU 利用率(实时)", "targets": [{"expr": "gpu_utilization_percent{device=\"0\"}"}], "type": "graph" }, { "title": "GPU 显存使用(MB)", "targets": [{"expr": "gpu_memory_used_bytes{device=\"0\"} / 1024 / 1024"}], "type": "graph" }, { "title": "API 请求总量(按任务类型)", "targets": [{"expr": "sum by (task_type) (rate(gte_api_requests_total[1h]))"}], "type": "stat" }, { "title": "P95 响应延迟(秒)", "targets": [{"expr": "histogram_quantile(0.95, sum(rate(gte_api_request_duration_seconds_bucket[1h])) by (le, task_type))"}], "type": "graph" } ] } }效果:4 个核心面板实时显示 GPU 负载、请求分布、关键延迟。你立刻能回答:“现在 NER 任务平均要 1.2 秒,但 P95 达到 4.7 秒,且 GPU 利用率持续 95% —— 很可能显存瓶颈。”
5. 实战验证与典型问题排查
5.1 快速验证监控是否生效
- 启动 Flask 应用:
bash /root/build/start.sh - 发送 3 类请求(各 2 次):
curl -X POST http://localhost:5000/predict -H "Content-Type: application/json" -d '{"task_type":"ner","input_text":"张三在北京工作"}' curl -X POST http://localhost:5000/predict -H "Content-Type: application/json" -d '{"task_type":"sentiment","input_text":"这个产品太棒了!"}' curl -X POST http://localhost:5000/predict -H "Content-Type: application/json" -d '{"task_type":"qa","input_text":"北京是中国的首都|北京是哪个国家的首都?"}' - 等待 30 秒,刷新 Grafana 看板 → 所有面板应有数据波动。
5.2 常见问题与解决
| 现象 | 原因 | 解决方案 |
|---|---|---|
http://<ip>:9090/metrics返回 404 | Flask 未正确挂载/metrics | 检查app.wsgi_app = DispatcherMiddleware(...)是否在app.run()之前执行;确认make_wsgi_app()导入无误 |
| Grafana 中 GPU 指标始终为 0 | pynvml未初始化或设备索引错误 | 在collect_gpu_metrics()函数开头加print(pynvml.nvmlDeviceGetName(handle)),确认设备名输出正常;多卡环境改用pynvml.nvmlDeviceGetHandleByIndex(i)循环采集 |
| Prometheus 抓取失败(State: DOWN) | Docker 网络隔离导致host.docker.internal不可达 | 将 Prometheus 的targets改为宿主机真实 IP(如172.16.1.100:9090),或启动时加--add-host=host.docker.internal:host-gateway |
/predict接口变慢 | 监控线程抢占 CPU? | collect_gpu_metrics中time.sleep(3)已足够宽松;实际延迟主要来自模型推理本身,监控开销 < 1ms,可忽略 |
进阶提示:若需告警(如 GPU 利用率 > 90% 持续 5 分钟),可在 Prometheus 中配置 Alert Rules,并通过邮件/Webhook 推送。本文聚焦可观测性基础,告警属于下一阶段。
6. 总结:监控不是锦上添花,而是上线必选项
部署一个大模型 Web 服务,从来不是git clone→pip install→bash start.sh就结束了。
真正的闭环,是当你看到 Grafana 上那条陡然拉升的 GPU 利用率曲线时,能立刻判断:“是新来的 QA 请求触发了显存泄漏”,而不是盲目重启;
是当运营同事说“分类功能最近不准”,你能打开看板,发现classification任务的 P95 延迟从 0.8 秒飙升至 6.2 秒,进而定位到某批脏数据导致模型反复重试;
是当服务器告警磁盘满,你第一反应不是删日志,而是查process_memory_bytes指标——确认是 Flask 进程内存缓慢增长,而非日志文件。
本文带你走完了从零到一的监控链路:
🔹 在现有 Flask 代码中轻量嵌入 Prometheus 指标(无侵入式改造);
🔹 用pynvml稳定采集 GPU 状态(避开nvidia-smi解析风险);
🔹 通过 Docker 一键拉起 Prometheus+Grafana(无需运维介入);
🔹 导入即用看板,5 分钟获得生产级可观测性。
下一步,你可以:
→ 将/metrics端点加上 Basic Auth(防未授权访问);
→ 用gunicorn替换app.run(),开启多 worker 并发(注意指标线程安全);
→ 把 Grafana 看板导出为 JSON,纳入 CI/CD 流水线自动部署。
监控不会让模型更准,但它让你永远清楚——它为什么不准。
--- > **获取更多AI镜像** > > 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。