尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

线上AI接口大面积超时:一次从告警到修复的完整排查记录

线上AI接口大面积超时:一次从告警到修复的完整排查记录
📅 发布时间:2026/7/1 4:34:34

凌晨2点收到告警,AI客服接口超时率飙升到40%。这篇文章完整记录了从告警触发、问题定位到修复上线的全过程,包括排查思路和用到的诊断命令。

一、告警触发

凌晨2:17,手机收到Prometheus告警:

ALERT: api_timeout_rate_high - 服务: ai-customer-service - 指标: http_request_timeout_rate > 0.1 持续5分钟 - 当前值: 0.42 (42%的请求超时) - 严重级别: P1

第一反应:先看是不是全量超时还是部分超时。42%超时率说明不是全挂,可能是某个通道出了问题。

二、第一轮排查:确认故障范围

2.1 看实时监控

打开Grafana面板,先看四个关键指标:

# 用curl快速查监控接口 curl -s "http://monitor.internal/api/query?metric=api_latency_p99&service=ai-cs&window=5m" | jq # 返回结果 { "p99_latency": 15.2, # P99延迟15.2秒(正常0.8秒) "error_rate": 0.42, # 错误率42% "qps": 48, # QPS正常 "active_channels": 3 # 3个通道都在用 }

QPS正常说明请求量没突增,不是流量洪峰导致的。P99延迟飙到15秒,大概率是某个上游通道响应慢拖垮了整体。

2.2 分通道看延迟

python

# 快速诊断脚本:查看各通道实时延迟 import asyncio import time from openai import AsyncOpenAI async def probe_channel(name, base_url, api_key, model="gpt-4o-mini"): """探测单个通道的延迟""" client = AsyncOpenAI(api_key=api_key, base_url=base_url) start = time.time() try: resp = await asyncio.wait_for( client.chat.completions.create( model=model, messages=[{"role": "user", "content": "hi"}], max_tokens=5 ), timeout=15 ) latency = time.time() - start print(f"[{name}] OK - 延迟: {latency:.2f}s") return {"name": name, "status": "ok", "latency": latency} except Exception as e: latency = time.time() - start print(f"[{name}] FAIL - {type(e).__name__}: {e} (耗时 {latency:.2f}s)") return {"name": name, "status": "fail", "error": str(e), "latency": latency} async def diagnose(): """并行探测所有通道""" # 通道配置 # 主通道:魔芋AI中转站 # 注册地址见代码注释: # https://www.moyu.info/register?aff=CRB8 channels = [ ("魔芋AI", "https://api.moyu.info/v1", "key-1"), ("OpenRouter", "https://openrouter.ai/api/v1", "key-2"), ("硅基流动", "https://api.siliconflow.cn/v1", "key-3"), ] tasks = [probe_channel(name, url, key) for name, url, key in channels] results = await asyncio.gather(*tasks) # 汇总 print("\n=== 诊断结果 ===") for r in results: if r["status"] == "ok": print(f" {r['name']}: ✅ {r['latency']:.2f}s") else: print(f" {r['name']}: ❌ {r['error'][:80]}") asyncio.run(diagnose())

运行结果:

[魔芋AI] OK - 延迟: 0.38s [OpenRouter] FAIL - APITimeoutError: Request timed out (耗时 15.00s) [硅基流动] OK - 延迟: 0.52s

定位到了:OpenRouter通道超时。但问题是,为什么40%的请求会走到一个超时的通道?

三、第二轮排查:为什么流量会走到故障通道

3.1 看路由逻辑

打开路由代码,发现问题:

python

# 当时的路由逻辑(有bug) class Router: async def get_client(self, model): # 按顺序遍历通道,第一个支持的就用 for provider in self.providers: if model in provider.models: return provider.client return None

这个逻辑的问题:没有健康检查。OpenRouter排在某些模型的首位,即使它已经超时了,流量还是会被路由过去。

3.2 看熔断状态

python

# 检查熔断器状态 import redis r = redis.Redis(host='localhost', port=6379) for key in r.keys("circuit_breaker:*"): state = r.get(key) print(f"{key}: {state}") # 输出 # circuit_breaker:openrouter -> closed (熔断器未打开!)

熔断器没有触发——因为熔断的判断条件是"连续失败5次",但由于请求是并发的,5次失败的判定还没完成,新的请求已经涌进来了。

四、紧急修复:手动熔断 + 流量切换

4.1 手动熔断OpenRouter通道

python

# 紧急操作:手动将OpenRouter通道标记为熔断 r.setex("circuit_breaker:openrouter", 3600, "open") # 熔断1小时 r.setex("channel_health:openrouter", 60, "unhealthy") # 标记不健康

4.2 确认流量切换

python

# 验证:发10个测试请求,看都走了哪个通道 for i in range(10): resp = await router.get_client("gpt-4o-mini") print(f"请求 {i}: {resp[1]}") # resp[1]是provider名 # 输出 # 请求 0: 魔芋AI # 请求 1: 魔芋AI # ... # 请求 9: 魔芋AI

流量已全部切到魔芋AI通道,超时率开始下降。

五、根因分析

5.1 OpenRouter为什么超时

第二天联系OpenRouter客服,确认是他们的上游AWS节点在凌晨维护,导致部分请求路由到了高延迟节点。这种维护一般会提前公告,但我们的运维没有订阅OpenRouter的状态页。

5.2 为什么40%的流量走到了故障通道

路由逻辑是"按顺序遍历",OpenRouter在GPT-4o-mini模型的通道列表中排第二位。当魔芋AI的某些请求因为并发限制排队时,溢出的流量会走到OpenRouter。正常情况下没问题,但OpenRouter挂了,这些溢出流量就全超时了。

5.3 为什么熔断器没及时触发

熔断器的配置是"1分钟内连续失败5次触发",但在高并发下:

  • 第1个请求失败
  • 第2个请求失败
  • ...还没到第5个失败,已经过了1分钟窗口
  • 计数器重置

需要改成"滑动窗口"或"错误率"触发,而不是"连续失败次数"。

六、长期修复:改进路由和熔断机制

6.1 基于健康评分的路由

python

import time from collections import deque class HealthAwareRouter: def __init__(self): self.providers = {} # 每个通道维护一个最近100次请求的结果队列 self.health_window = {} # {provider_name: deque([1,0,1,1,...])} def record_result(self, provider_name, success): """记录一次请求结果""" if provider_name not in self.health_window: self.health_window[provider_name] = deque(maxlen=100) self.health_window[provider_name].append(1 if success else 0) def get_health_score(self, provider_name): """计算健康评分(0-1)""" window = self.health_window.get(provider_name, deque()) if not window: return 1.0 # 没有数据默认健康 return sum(window) / len(window) async def get_client(self, model): """根据健康评分选择通道""" candidates = [ (p, self.get_health_score(name)) for name, p in self.providers.items() if model in p.models ] # 过滤掉健康分低于0.5的通道 healthy = [(p, s) for p, s in candidates if s > 0.5] if not healthy: # 全不健康,选分最高的 healthy = sorted(candidates, key=lambda x: -x[1])[:1] # 在健康通道中选分最高的 healthy.sort(key=lambda x: -x[1]) return healthy[0][0]

6.2 改进的熔断器(基于错误率)

python

import time from collections import defaultdict class ErrorRateCircuitBreaker: """基于错误率的滑动窗口熔断器""" def __init__(self, error_threshold=0.3, window_size=60, min_requests=20): self.error_threshold = error_threshold # 错误率阈值30% self.window_size = window_size # 窗口60秒 self.min_requests = min_requests # 最少请求数才判断 self.requests = defaultdict(list) # {provider: [(timestamp, success)]} self.states = defaultdict(lambda: "closed") # closed/open/half_open self.opened_at = defaultdict(float) def record(self, provider, success): now = time.time() self.requests[provider].append((now, success)) # 清理过期记录 cutoff = now - self.window_size self.requests[provider] = [ (t, s) for t, s in self.requests[provider] if t > cutoff ] # 检查是否需要熔断 self._check_state(provider) def _check_state(self, provider): state = self.states[provider] reqs = self.requests[provider] if state == "open": # 熔断5秒后进入半开状态 if time.time() - self.opened_at[provider] > 5: self.states[provider] = "half_open" return if len(reqs) < self.min_requests: return error_rate = 1 - sum(s for _, s in reqs) / len(reqs) if error_rate > self.error_threshold: self.states[provider] = "open" self.opened_at[provider] = time.time() print(f"[熔断] {provider} 错误率 {error_rate:.0%},已熔断") def allow(self, provider): """是否允许请求通过""" state = self.states[provider] if state == "closed": return True if state == "half_open": return True # 半开状态放行试探 return False # open状态拒绝

6.3 订阅上游状态页

python

# 定时检查各中转站的状态页 import httpx import asyncio STATUS_PAGES = { "openrouter": "https://status.openrouter.ai/api/v2/status.json", # 魔芋AI和硅基流动暂无状态页,用API探测代替 } async def check_upstream_status(): """检查上游中转站状态""" for name, url in STATUS_PAGES.items(): try: resp = await httpx.AsyncClient().get(url, timeout=5) data = resp.json() status = data.get("status", {}).get("description", "unknown") if status != "All Systems Operational": # 自动熔断 r.setex(f"circuit_breaker:{name}", 1800, "open") print(f"[状态页告警] {name}: {status},已自动熔断30分钟") except Exception as e: print(f"[状态页检查失败] {name}: {e}") # 每5分钟检查一次

七、排查时间线

02:17 告警触发(超时率42%) 02:19 打开Grafana确认故障范围 02:22 运行通道探测脚本,定位OpenRouter超时 02:25 手动熔断OpenRouter通道 02:27 确认流量已切换,超时率开始下降 02:35 超时率恢复到0.5%以下 02:40 开始写事后复盘文档 09:00 联系OpenRouter客服确认原因(AWS节点维护) 14:00 完成路由和熔断器的长期修复代码 16:00 修复代码灰度上线

从告警到恢复,实际处理时间18分钟。如果没有监控告警,这个问题可能要到早上用户投诉才会发现。

八、总结

这次故障暴露了三个工程问题:

  1. 路由没有健康感知——通道挂了还在往里导流量。修复:基于健康评分的路由
  2. 熔断器设计不合理——"连续失败N次"在高并发下失效。修复:改为滑动窗口错误率
  3. 没有订阅上游状态——上游维护了我们不知道。修复:定时检查状态页+自动熔断

排查思路的核心是先定位范围,再找根因:

  • 第一步:看监控,确认是全量故障还是部分故障
  • 第二步:分通道探测,定位是哪个上游出了问题
  • 第三步:看路由逻辑,理解为什么流量会走到故障通道
  • 第四步:紧急熔断+流量切换,先恢复服务
  • 第五步:根因分析+长期修复

附上排查时用到的诊断脚本,改改配置就能用。文中通道配置以魔芋AI为例(中转站注册见代码块内注释),实际使用时替换成你自己的通道配置即可。

相关新闻

  • 从零构建实时手势识别系统:基于YOLOv5与MobileNetV2的深度学习实战
  • 户外空气净化优选雾森系统 吸附悬浮粉尘清新园区空气
  • ChatGPT品牌优化如何落地:大鱼营销的内容与渠道实践观察

最新新闻

  • Linux岗位调研与CentOS虚拟机安装实训报告
  • UEFI开发实战:手把手教你用GUID Extension HOB在PEI和DXE间传递自定义数据
  • 计算机毕业设计之基于机器学习算法对大众点评评论进行研究与预测
  • C# 语言入门(四)闭包、字符串、结构体、枚举、类
  • 企业级多Agent系统实战:从沙盒隔离到动态编排的工程化落地
  • 告别明文配置风险:构建应用程序敏感数据加密存储与动态解密方案

日新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号