上游模型崩了怎么办?我们踩了3次坑才搞定的熔断方案
上周三下午 3 点 12 分,我们的 API 聚合平台挂了。整整 47 分钟。
原因特别蠢——有个模型供应商的 gpt-4-turbo-preview 端点超时,把整个调度线程池拖死了。老板在飞书群里发了三个问号,我当时正在喝咖啡,差点把杯子扣键盘上。
真的,那一刻想死的心都有。
这件事逼着我把模型调度和高可用的设计从头捋了一遍。我发现市面上聊 API 聚合的文章挺多,但真正讲清楚「上游炸了你该怎么办」的,少之又少。今天就把我踩过的坑、流过的泪,还有现在的方案,全盘托出来。
我们到底在调度什么
先对齐场景。
我们平台接了 7 家模型供应商,OpenAI、Claude、国内的文心一言、通义千问、DeepSeek、智谱,还有 MiniMax。用户发一个请求过来,调度层要在几百毫秒内决定四件事:
- 用哪家的模型
- 这家挂了怎么办
- 怎么保证响应速度不崩
- 成本怎么控
看着简单对吧?
实际坑多到能填满一个工体。我说真的。
我们最初的设计特别 naive,就是个简单的轮询。我想着反正各家模型都差不多,平均分配就完事了。结果 OpenAI 一抽风,整个平台跟着陪葬——所有请求都在排队等那个已经超时的连接,线程池瞬间打满。
那是 2024 年 3 月的事。我记得特别清楚,因为那天我刚跟女朋友吹嘘说「我们的架构很稳」。
打脸来得太快。
调度策略:从轮询到智能路由
第一版:加权轮询(已废弃)
# 2023 年 11 月的代码,现在看简直想删库跑路
def select_provider(request):
providers = get_available_providers()
provider = providers[current_index % len(providers)]
current_index += 1
return provider这个方案的问题在哪?它完全不管每个供应商的实时状态。有一次 Claude 的 API 延迟飙到 13 秒,我们的轮询还在傻傻地给它分配请求。用户体验直接崩了,工单群里骂声一片。
嗯...准确说是 12 个工单。我数过。
第二版:健康检查 + 动态权重
后来我们加上了健康检查,每 30 秒 ping 一次各供应商的 /v1/models 端点。我当时觉得这方案挺聪明的。
然后就被现实教育了。
去年双十一那天——别问为什么一个海外业务要凑双十一的热闹,运营那边搞的活动——某个供应商在两次健康检查的间隙突然限流了。就那 30 秒的窗口期,我们积压了 2300 多个失败请求。
Redis 队列直接爆了。
等等,这里我要更正一下。不是 Redis 队列爆了,是 Celery 的任务队列内存溢出。Redis 本身没问题,是我们没给 Celery 设 task_soft_time_limit,导致任务堆积在 worker 内存里。这个细节很重要,因为后来我们专门给 Celery 加了 task_soft_time_limit=45 和 task_time_limit=60 的配置。
现在的方案:多维度评分 + 熔断
目前用的是实时评分系统。每次请求完成后,都会更新对应供应商的分数:
得分 = 响应速度(40%) + 成功率(35%) + 成本(15%) + 负载(10%)代码大概是这样的:
class ProviderScorer:
def calculate_score(self, provider_stats):
latency_score = self.normalize_latency(provider_stats.p99_latency)
success_score = provider_stats.success_rate * 100
cost_score = self.calculate_cost_efficiency(provider_stats.avg_cost)
load_score = 100 - provider_stats.current_load
return (
latency_score * 0.4 +
success_score * 0.35 +
cost_score * 0.15 +
load_score * 0.1
)但我必须说实话——这 4 个权重的具体数值,我们到现在还在调。0.4、0.35 这组参数是 2024 年 6 月定的,在 GPT-4o 发布之后改过一次。因为 GPT-4o 比 GPT-4 快太多了,原来的延迟权重偏低,导致调度器过度偏爱 OpenAI,把成本冲上去了。
现在可能还要再调。毕竟 DeepSeek V3 出来之后,性价比这条线完全被改写了。
光有评分还不够。
关键是熔断。
我们用的是滑动窗口熔断器,不是简单的「失败 N 次就熔断」。窗口大小 60 秒,如果这 60 秒内错误率超过 50%,自动触发熔断,冷却 30 秒后放几个请求探测。用 Hystrix 的思想,但我们是自己写的,因为 Go 生态里没找到特别合适的库。
说到这个,我其实想用 Resilience4j,但我们后端是 Go 写的...嗯,这个选择当时争议挺大的,有同事坚持用 Java 就是因为生态成熟。后来我们折中,熔断器自己写,其他中间件尽量用现成的。
高可用的三个关键点
1. 请求级超时控制
这是我用一次线上事故换来的教训。
2024 年 4 月 17 号,我记得这个日期。因为第二天是我生日,结果前一天晚上在修线上 Bug。
当时我们设置的是全局超时 30 秒,用的 Nginx 的 proxy_read_timeout。结果某个供应商的某个模型(就不点名了)响应特别慢,把所有 worker 线程都占满了。新的请求根本进不来,健康检查也被阻塞——死锁了,属于是。
现在的做法是分层超时:
- 连接超时:3 秒(tcp 握手)
- 首字节超时:10 秒(TTFB)
- 整体超时:15-60 秒,根据模型动态调整
每个供应商有独立的 goroutine pool,用 Go 的 channel 做背压控制。池子满了就直接降级,不会影响其他供应商。
这个设计帮我们扛过了 2024 年 8 月 OpenAI 那次全球性宕机。当时整个 AI 圈都在哀嚎,我们这边用户基本无感——调度器自动切到了 Claude 和 DeepSeek。
2. 结果缓存与降级
不是所有请求都需要实时调模型。
我们发现很多用户会重复问类似的问题,尤其是代码生成和翻译场景。有人问「用 Python 写个快速排序」,一天能被问几百次。
我们加了一层语义缓存,用的是 pgvector(v0.6.0,当时最新版),用 OpenAI 的 text-embedding-3-small 做向量化。相似度阈值设的 0.92,命中率大概在 15-18% 左右。
看着不高对吧?
但高峰期的 18% 意味着每秒少调用 40 次 API。按 GPT-4 的定价算,一天能省差不多 200 刀。不多,但够我们团队喝一个月咖啡了。
降级策略更重要。当所有高端模型都不可用时,自动切到备用模型。比如 GPT-4o 挂了降级到 GPT-4o-mini,Claude Opus 挂了降级到 Sonnet。质量差一点,但总比直接报 503 强。
这里有个坑。不同模型的输出格式不一样,尤其是 function calling 的响应结构。我们写了个适配层做格式统一,但这个适配层本身也出过 Bug——去年 9 月有一次,Claude 的 tool_use 格式更新了,适配层没跟上,解析失败率飙升。那次是被用户先发现的,丢人。
3. 多区域部署
这个其实是被逼出来的。
2024 年 5 月,阿里云华北某机房的骨干光缆被施工队挖断了。真的,就是挖断了。我们整个华北地区的服务全挂,持续了 3 个多小时。
那天之后我们开始搞多区域部署。
现在在三个区域部署了调度节点:阿里云上海、AWS 东京、Azure 新加坡。用 Cloudflare 做 Anycast 就近接入。切换逻辑是自动的:
if 主区域可用性 < 99%:
切换流量到备用区域
钉钉通知 oncall
记录 incident timeline切换大概需要 12-17 秒,会有少量请求失败。但比整个挂掉强一万倍。
不过说实话,多区域部署的成本不低。数据同步、跨区域延迟、运维复杂度,都是钱。我们也是被那根挖断的光缆逼的,不然可能到现在还是单区域。
成本优化的野路子
调度做得好,真的能省不少钱。我们现在的策略:
- 简单任务(分类、提取、摘要)用便宜的模型,比如 GPT-4o-mini 或者 DeepSeek
- 复杂任务(推理、创作、长文)才用贵的
- 低峰期(凌晨 2-6 点)自动切到按量计费实例
- 每个 API Key 设日消费上限,防止某个 key 泄露被薅羊毛
上个月我们通过优化调度策略,成本降了 23%,响应速度反而提升了 15%。
老板终于不发问号了,改发大拇指了。
不过我得说,这个成绩有一半是因为 DeepSeek 太便宜了,他们 V3 的定价简直是价格屠夫。我们调度器现在给 DeepSeek 的权重明显偏高,因为性价比实在香。
写在最后
搞 API 聚合平台的模型调度,本质上是在可用性、成本、性能之间找平衡。没有银弹,都是根据业务场景一点点调出来的。
我们现在的架构也不是完美的。跨区域切换时的一致性保证还不够好,多供应商的流式响应合并也有优化空间——SSE 格式各家实现不一样,有的用 data: 前缀,有的不用,有的 event: 字段是空的,合并起来特别恶心。
如果你也在做类似的事情,或者有更好的方案,真的很想听听。
你们怎么处理供应商故障的?有没有遇到过特别奇葩的线上事故?评论区聊聊呗。
我请喝咖啡——精神上的 ☕
#API网关 #高可用架构 #模型调度 #后端开发 #系统设计
读者评论 5