监控指南
| English | 中文 |
|—|—|
本指南涵盖 Mortred Model Server 监控体系的完整生命周期:部署、配置、指标含义、仪表盘解读、告警响应与故障排查。适用于运维人员(SRE / DevOps)与服务管理员。
架构概览
┌─────────────────────────────────────────────────────────────┐
│ 监控数据流 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ /metrics ┌──────────────┐ │
│ │ 网关 │ ───────────→ │ │ │
│ │ (:8080) │ │ Prometheus │ │
│ └──────────┘ │ (:9090) │ │
│ │ 抓取+存储 │ │
│ ┌──────────┐ /metrics │ +告警评估 │──→ 告警通知 │
│ │ 监督器 │ ───────────→ │ │ (可选) │
│ │ (:8787) │ └──────┬───────┘ │
│ └──────────┘ │ │
│ ┌──────▼───────┐ │
│ ┌──────────┐ /metrics │ Grafana │ │
│ │ 模型服务器 │ ───────────→ │ (:3000) │ │
│ │(仅环回) │ │ 可视化面板 │ │
│ └──────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
默认刮取目标是网关 :8080/metrics,含环回在内一律需要
MORTRED_METRICS_TOKEN。监督器 :8787/api/v1/metrics
需要管理 Bearer token。模型 /metrics 仅环回,且在监督器注入了
MORTRED_AUTH_TOKEN 时需要同一 Bearer。不要为了刮指标而映射模型端口。
快速开始
方式一:Docker Compose 一键部署(推荐)
export GRAFANA_ADMIN_PASSWORD="$(openssl rand -hex 16)"
set -a && . conf/local/trust.env && set +a # 必须含 MORTRED_METRICS_TOKEN
./scripts/write_prometheus_credentials.sh # chown 65534:65534(可能要 sudo)
docker compose -f deploy/docker-compose.monitoring.yml up -d
# Grafana: http://localhost:3000(用户 admin / $GRAFANA_ADMIN_PASSWORD)
# Prometheus: http://localhost:9090(仅环回)
# Prometheus 数据源与 Mortred dashboard 已 provisioning。
# compose 刮 host.docker.internal:8080(prometheus.compose.yml)。
# 容器内 localhost:8080 是 Prometheus 自己,不是 Mortred。
方式二:裸机部署
sudo apt install prometheus grafana
sudo cp deploy/prometheus.yml /etc/prometheus/prometheus.yml
sudo cp deploy/alert-rules.yml /etc/prometheus/alert-rules.yml
set -a && . conf/local/trust.env && set +a
sudo ./scripts/write_prometheus_credentials.sh /etc/prometheus/mortred_metrics_token
sudo systemctl restart prometheus
方式三:Prometheus 单独运行
prometheus --config.file=deploy/prometheus.yml --storage.tsdb.path=/tmp/prom-data
指标来源
| 组件 |
端口 |
端点 |
说明 |
| 网关 |
:8080 |
/metrics |
推理入口(含环回一律要 MORTRED_METRICS_TOKEN) |
| 监督器 |
:8787 |
/api/v1/metrics |
进程管理(需要 Bearer MORTRED_API_TOKEN) |
| 模型服务器 |
环回 :9001-9084 |
/metrics |
与 Prometheus 同一网络命名空间;不要映射这些端口 |
添加新模型抓取
仅当 Prometheus 能打到模型的环回端口时(host 网络,或与 systemd 同机)。
永远不要为了刮指标而 docker publish 模型端口。
- job_name: mortred-model-yolov5
static_configs:
- targets: ['localhost:9053']
labels: { component: model, model: yolov5 }
指标参考
可用性(3 个)— “服务是否活着”
| 指标 |
类型 |
说明 |
mortred_up |
gauge |
进程存活 (1=活) |
mortred_ready |
gauge |
有可用 worker (1=就绪) |
up |
gauge |
Prometheus 可抓取 (1=可达) |
mortred_up vs up:前者是进程自报告,后者是 Prometheus 外部探测。up == 0 是更可靠的宕机信号。
流量(3 个)— “有多少请求”
| 指标 |
类型 |
标签 |
说明 |
mortred_http_requests_total |
counter |
model, method, status |
HTTP 请求累计(含异步任务端点;异步回复不产生时长样本) |
mortred_http_request_duration_ms |
histogram |
model, method, status |
请求耗时(毫秒) |
mortred_queue_rejected_total |
counter |
model |
429 拒绝累计 |
# 每秒请求数
sum(rate(mortred_http_requests_total[5m]))
# 按模型的 p95 延迟
histogram_quantile(0.95, sum(rate(mortred_http_request_duration_ms_bucket[5m])) by (le, model))
# 5xx 错误率
100 * sum(rate(mortred_http_requests_total{status=~"5.."}[5m])) by (model)
/ sum(rate(mortred_http_requests_total[5m])) by (model)
推理(7 个)— “模型本身表现”
| 指标 |
类型 |
说明 |
mortred_inference_duration_ms |
histogram |
模型推理耗时(不含排队) |
mortred_queue_wait_duration_ms |
histogram |
等待 worker 耗时 |
mortred_inference_success_total |
counter |
成功推理累计 |
mortred_inference_failure_total |
counter |
失败推理累计 |
mortred_model_output_contract_failures_total |
counter |
???? dtype/shape/buffer ?????? |
mortred_workers_busy |
gauge |
繁忙 worker 数 |
mortred_workers_available |
gauge |
空闲 worker 数 |
mortred_queue_depth |
gauge |
排队深度 |
诊断:p95 延迟高时,先看 queue_depth——深排队 → 容量不足(加 worker);浅排队但慢 → 模型/GPU 问题。
批处理(2 个)— “批处理是否有效”
| 指标 |
类型 |
说明 |
mortred_batch_size |
histogram |
实际执行批大小 |
mortred_batch_window_wait_ms |
histogram |
批收集窗口等待 |
# 平均批大小(> 1.5 说明有效)
sum(mortred_batch_size_sum) by (model) / sum(mortred_batch_size_count) by (model)
异步任务(3 个)— “长任务状态”
| 指标 |
类型 |
说明 |
mortred_async_jobs_total |
counter |
按状态计数(submitted/running/done/failed/timeout) |
mortred_async_queue_depth |
gauge |
异步队列深度 |
mortred_async_job_duration_ms |
histogram |
异步任务耗时 |
监督器(3 个)— “进程管理”
| 指标 |
类型 |
说明 |
mortred_supervisor_state |
gauge |
进程状态码 |
mortred_supervisor_ready |
gauge |
进程就绪 (1) |
mortred_supervisor_restarts_total |
counter |
重启累计 |
状态码:
| 值 |
状态 |
含义 |
| 0 |
stopped |
已停止 |
| 1 |
starting |
启动中 |
| 2 |
running |
正常运行 |
| 3 |
backoff |
重启退避中 |
| 4 |
failed |
崩溃循环放弃 |
告警参考
告警概览(12 条 × 5 组)
可用性(4 条)
| 告警 |
级别 |
触发 |
含义 |
响应 |
| GatewayDown |
critical |
网关 30 秒不可达 |
推理流量全断 |
检查网关进程 |
| SupervisorDown |
critical |
监督器 60 秒不可达 |
进程管理丢失 |
检查 supervisor |
| ModelServerDown |
warning |
模型 60 秒不可达 |
单模型不可用 |
查看该模型日志 |
| ModelNotReady |
warning |
就绪探针失败 2 分钟 |
进程在但不可用 |
检查模型加载 |
性能(5 条)
| 告警 |
级别 |
触发 |
含义 |
响应 |
| HighQueueDepth |
warning |
深度 > 20 持续 60 秒 |
排队过长 |
加 worker 或扩容 |
| OverloadRejections |
warning |
429 > 0.1/s 持续 2 分钟 |
开始拒绝请求 |
增大 max_queue_depth |
| HighLatency |
warning |
p95 > 2000ms 持续 5 分钟 |
推理变慢 |
检查 GPU / 模型 |
| HighErrorRate |
critical |
5xx > 5% 持续 2 分钟 |
大量推理失败 |
查看模型日志 |
| AllWorkersBusy |
critical |
0 空闲 worker 持续 2 分钟 |
可能卡死 |
检查 stuck-worker |
异步(2 条)
| 告警 |
级别 |
触发 |
响应 |
| AsyncQueueFull |
warning |
异步深度 > 10 持续 2 分钟 |
检查异步 worker 数 |
| AsyncTimeouts |
warning |
超时 > 0.05/s |
检查 async_timeout |
批处理(1 条)
| 告警 |
级别 |
触发 |
响应 |
| BatchNotCoalescing |
info |
平均批 < 1.5 持续 10 分钟 |
检查并发量和 delay |
监督器(1 条)
| 告警 |
级别 |
触发 |
响应 |
| RestartStorm |
critical |
重启 > 0.2/s 持续 2 分钟 |
查崩溃原因 |
级别与响应
| 级别 |
含义 |
通知 |
响应时间 |
| critical |
服务不可用 |
电话/短信 |
< 5 分钟 |
| warning |
性能退化 |
Slack/邮件 |
< 30 分钟 |
| info |
优化建议 |
仪表盘 |
下次巡检 |
自定义告警
- alert: MortredCustomGPUHigh
expr: your_gpu_metric > 90
for: 300s
labels: { severity: warning }
annotations:
summary: "GPU 使用率过高"
curl -X POST http://localhost:9090/-/reload # 热加载
Grafana 仪表盘
导入
Dashboard → Import → 上传 deploy/grafana-dashboard.json → 选择 Prometheus 数据源 → Import
compose 栈会 provision Prometheus 数据源(uid: prometheus)并从
/var/lib/grafana/dashboards 加载该 JSON;只有没走这套 provisioning 的
Grafana 才需要 Import 界面。
面板解读
第一行:全局概览
| # |
面板 |
看什么 |
| 1 |
服务可用性 |
全绿 = 正常;红 = 有宕机 |
| 2 |
推理速率 |
流量趋势;突降 = 异常 |
| 3 |
错误率 |
正常 < 1%;突升 = 模型问题 |
| 4 |
过载拒绝 |
非零 = 过载开始 |
第二行:性能
| # |
面板 |
看什么 |
| 5 |
延迟 p50/p95/p99 |
p99 突刺 = 个别慢请求 |
| 6 |
队列深度 |
持续上升 = 容量不足 |
| 7 |
Worker 状态 |
busy = total → 满载 |
第三行:批处理与异步
| # |
面板 |
看什么 |
| 8 |
批大小 |
平均 > 1.5 = 批有效 |
| 9 |
批窗口等待 |
过高 = delay 太大 |
| 10 |
异步任务 |
done 上升正常;timeout 上升异常 |
第四行:系统健康
| # |
面板 |
看什么 |
| 11 |
异步队列深度 |
> 10 = 积压 |
| 12 |
进程状态 |
2=绿(运行)、4=红(失败) |
| 13 |
重启率 |
非零持续 = 崩溃循环 |
故障排查
Prometheus 抓取失败
curl -s http://localhost:9090/api/v1/targets | \
jq '.data.activeTargets[] | select(.health != "up") | {job: .labels.job, error: .lastError}'
常见原因:模型未运行 / 端口错误 / Docker 网络(用 host.docker.internal)
指标缺失
curl -s -H "Authorization: Bearer $MORTRED_METRICS_TOKEN" \
http://localhost:8080/metrics | head -5
常见原因:进程未运行 / 端口不对 / 缺少 scrape token /
Prometheus 在 Docker 里仍指向 localhost 而不是 host.docker.internal
告警不触发
curl -s http://localhost:9090/api/v1/rules | \
jq '.data.groups[].rules[] | select(.type == "alerting") | {name, state}'
curl -s 'http://localhost:9090/api/v1/query?query=mortred_queue_depth' | jq '.data.result'
常见原因:表达式标签不匹配 / for 时长未达到 / 告警被静默
Grafana 面板无数据
curl -s http://localhost:3000/api/datasources | jq '.[] | {name, type, url}'
确保 Prometheus URL 正确,在 Explore 中手动测试查询。
手动验证命令汇总
# 网关(含环回也要 scrape Bearer)
curl -s -H "Authorization: Bearer $MORTRED_METRICS_TOKEN" \
http://localhost:8080/metrics | head -20
curl -s -H "Authorization: Bearer $MORTRED_METRICS_TOKEN" \
http://localhost:8080/metrics | grep mortred_http_requests_total
# 模型服务器(在跑模型的那台机器上打环回;不要 -p 这些端口)
curl -s http://localhost:9002/metrics | grep mortred_up
curl -s http://localhost:9002/metrics | grep mortred_queue_depth
curl -s http://localhost:9002/metrics | grep mortred_workers
curl -s http://localhost:9002/metrics | grep mortred_batch_size
curl -s http://localhost:9002/metrics | grep mortred_async
# 监督器
curl -s -H "Authorization: Bearer $MORTRED_API_TOKEN" \
http://localhost:8787/api/v1/metrics
# Prometheus
curl -s http://localhost:9090/api/v1/targets | \
jq '.data.activeTargets[] | {job: .labels.job, health: .health}'
curl -s http://localhost:9090/api/v1/alerts | \
jq '.data.alerts[] | {name: .labels.alertname, state}'
# 手动查询
curl -s 'http://localhost:9090/api/v1/query?query=mortred_up' | jq .
curl -s 'http://localhost:9090/api/v1/query?query=rate(mortred_http_requests_total[5m])' | jq .
最佳实践
抓取间隔与保留
global:
scrape_interval: 15s # 高流量可降到 5s
evaluation_interval: 15s
prometheus --storage.tsdb.retention.time=30d # 保留 30 天
阈值调优
| 指标 |
初始值 |
调优建议 |
| queue_depth |
> 20 |
观察 1 周按 P99 调 |
| p95 latency |
> 2000ms |
按模型类型分组(分类 < 100ms,检测 < 500ms) |
| 5xx rate |
> 5% |
高可靠可降到 1% |
| restart rate |
> 0.2/s |
偶尔重启可放宽到 0.1/min |
覆盖度检查清单