三层监控系统设计:从API日志到DevOps健康检查
摘要:当AI应用上线后,如何第一时间发现响应变慢、任务堆积或数据库连接耗尽?本文基于一个真实的跑步教练AI项目,详细解析如何构建"微观-中观-宏观"三层监控体系。我们将深入源码,结合流程图和调用链,展示如何实现全链路Trace ID追踪、P95/P99延迟计算、任务队列深度监控以及基础设施健康检查。这套方案帮助我们在用户投诉前就发现了80%的潜在故障,是保障生产环境稳定性的核心防线。
一、背景:黑盒运行的焦虑
在项目初期,系统就像一个黑盒:
- 用户说卡:我不知道是LLM慢了,还是数据库锁了。
- 任务丢了:异步队列里到底有多少任务在排队?完全靠猜。
- 资源盲区:服务器内存是不是快爆了?只能等宕机了才知道。
为了解决这些"盲人摸象"的问题,我设计了三层监控架构。
二、整体架构:微观、中观与宏观
Layer 3: 宏观监控 (DevOps Level)
Layer 2: 中观监控 (API Level)
Layer 1: 微观监控 (Task Level)
Task Queue Metrics
队列深度/Worker状态
Agent Execution Log
单步耗时/Token消耗
API Logger Middleware
P95延迟/状态码分布
Slow Request Alert
慢请求捕获
System Health Check
CPU/内存/磁盘
External Dependencies
Redis/PostgreSQL连通性
三、Layer 1:微观监控------任务队列透视
3.1 实时监控指标
对于异步任务队列,我们最关心的是积压情况 和处理效率。
文件位置:app/services/task_metrics.py
python
class TaskMetrics:
def get_snapshot(self) -> Dict:
return {
"queue_depth": task_queue.queue.qsize(), # 当前排队数
"active_workers": count_active_workers(), # 忙碌的Worker数
"processing_rate": calc_avg_rate(), # 每分钟处理任务数
"dlq_count": len(dead_letter_queue.tasks) # 死信队列积压
}
告警阈值:
- 当
queue_depth > 500时,触发"任务积压"告警。 - 当
dlq_count持续增长时,说明有系统性Bug。
四、Layer 2:中观监控------API性能画像
4.1 全链路Trace ID
为了让每一个请求都可追溯,我们在中间件层注入了唯一的 trace_id。
文件位置:app/middleware/monitoring_middleware.py
python
async def dispatch(self, request: Request, call_next):
trace_id = str(uuid.uuid4())
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
# 记录结构化日志
logger.info({
"event": "request_completed",
"trace_id": trace_id,
"path": request.url.path,
"method": request.method,
"status": response.status_code,
"duration_ms": round(process_time * 1000, 2)
})
return response
4.2 P95/P99延迟计算
平均延迟往往会掩盖长尾问题。我们通过滑动窗口实时计算P95(95%的请求都快于这个值)。
python
class LatencyTracker:
def __init__(self):
self.latencies = deque(maxlen=1000) # 保留最近1000次请求
def record(self, duration_ms: float):
self.latencies.append(duration_ms)
def get_percentile(self, p: int) -> float:
if not self.latencies: return 0
sorted_latencies = sorted(self.latencies)
index = int(len(sorted_latencies) * p / 100)
return sorted_latencies[min(index, len(sorted_latencies)-1)]
实际意义:如果P95从2秒飙升到10秒,说明系统出现了明显的性能抖动,即使平均值看起来还正常。
五、Layer 3:宏观监控------DevOps健康检查
5.1 综合健康端点
文件位置:app/api/health_api.py
python
@router.get("/health")
async def health_check():
checks = {
"api": "ok",
"database": await check_postgres(),
"redis": await check_redis(),
"llm_gateway": await check_litellm()
}
status = "healthy" if all(v == "ok" for v in checks.values()) else "degraded"
return {"status": status, "checks": checks}
5.2 外部依赖探测
我们不仅监控自己,还监控"队友":
- PostgreSQL :执行一个简单的
SELECT 1。 - Redis :执行
PING。 - LLM Gateway:发送一个极小的测试Prompt,确保模型网关没挂。
六、完整调用链追踪
6.1 故障排查实战
场景:用户反馈"生成计划特别慢"。
排查步骤:
- 查宏观 :访问
/health,发现Redis状态为degraded。 - 查中观:查看API日志,发现所有接口的P95延迟都增加了500ms。
- 查微观:检查Task Metrics,发现Worker处理速度变慢,因为它们在等待Redis限流响应。
- 结论:Redis所在服务器网络波动,导致全链路延迟。
七、踩坑记录与解决方案
坑1:日志写得太勤,拖慢系统
现象:每个步骤都写数据库日志,导致写入成为瓶颈。
解决方案:
- 异步写入:日志先存入内存Queue,由后台线程批量Flush到DB。
- 采样记录:对于高频接口,只记录10%的详细日志。
坑2:监控数据本身占用过多内存
现象 :LatencyTracker里的deque存了太多数据。
解决方案 :设置严格的 maxlen,并定期将聚合后的统计数据(如每分钟平均延迟)存入Redis,原始数据直接丢弃。
八、总结与展望
核心价值
- 主动发现:在用户感知到卡顿之前,P95指标已经发出了预警。
- 精准定位:Trace ID让我们能迅速锁定是哪个环节(DB、LLM还是网络)出了问题。
- 全局视野:从任务细节到服务器负载,一站式掌握系统脉搏。
后续优化
- 可视化面板:集成Grafana,将监控指标转化为动态图表。
- 智能告警:利用AI分析日志模式,自动识别异常波动而非死板的阈值。
九、完整源码
GitHub仓库 :AiRunCoachAgent
快速演示 :AiRunCoachAgent
核心文件清单:
app/
├── middleware/
│ └── monitoring_middleware.py # API层监控
├── services/
│ ├── task_metrics.py # 任务队列监控
│ └── devops_metrics.py # 基础设施监控
├── api/
│ └── health_api.py # 健康检查端点
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、转发!有任何问题或建议,请在评论区留言讨论。 🏃♂️💨