结论先行: 限流、重试、熔断和故障切换解决的是四类不同问题。限流控制请求进入的速度。重试处理瞬时失败。熔断在上游持续故障时暂停发送。故障切换把请求转给备用上游或模型组。把四者混在一起用,最常见的后果是故障被放大:每层都重试,同一个失败会变成几十次上游请求。
机制 | 解决的问题 | 作用位置 | 常见误用 |
|---|---|---|---|
限流 | 请求超过配额,上游拒绝 | 网关入口,按 Key、模型或团队 | 只设全局总量,一个团队占满额度 |
退避重试 | 偶发超时、短暂 429、瞬时 5xx | 单次调用,同一上游 | 对额度耗尽也重试 |
熔断 | 上游持续失败,继续发送只会加重故障 | 上游的健康状态 | 阈值过低,短暂抖动就断开 |
故障切换 | 某个上游或模型组不可用 | 路由层 | 切换到能力不同的模型,输出随之变化 |
几个指标需要区分:
指数退避加抖动(exponential backoff with jitter)是常用的重试间隔策略。每次等待时间按指数增长,并加入随机量,使大量客户端不会在同一时刻重试。AWS 架构博客对此有分析 1。
一次请求在网关内的处理顺序如下:
错误类型 | 处理动作 | 是否重试同一上游 | 是否切换上游 | 是否计入熔断 |
|---|---|---|---|---|
429 且带等待时间 | 等待后重试 | 是,次数有限 | 否 | 否 |
额度耗尽 | 不重试,切换或返回 | 否 | 是(同模型组的其他上游) | 否,但标记该上游额度不足 |
5xx 或超时 | 退避重试 | 是,次数有限 | 重试耗尽后切换 | 是 |
参数错误 | 直接返回 | 否 | 否 | 否 |
上表描述的是设计思路。各产品的实际处理方式以其文档为准,判断某个错误属于哪一类,需要依据各供应商的错误码映射。
下面是上游选择和重试次数控制的设计示例,未经测试,仅用于说明判断顺序:
MAX_RETRY_PER_UPSTREAM = 2
def call_with_failover(request, upstreams):
for upstream in upstreams:
if upstream.circuit_open():
continue
for attempt in range(MAX_RETRY_PER_UPSTREAM + 1):
resp = upstream.send(request)
if resp.ok:
upstream.record_success()
return resp
if resp.error_type == "quota_exhausted":
upstream.mark_quota_low()
break
if resp.error_type == "bad_request":
return resp
upstream.record_failure()
if upstream.circuit_open() or attempt == MAX_RETRY_PER_UPSTREAM:
break
sleep(backoff_with_jitter(attempt))
raise AllUpstreamsFailed()实现时要注意两点。第一,重试次数是每个上游的上限,而不是每层各自的上限。第二,流式响应一旦开始输出,就很难在中途切换上游,切换通常只能在第一个 Token 返回前进行。
重试放大的数字可以直接算。如果客户端、网关和上游代理各重试 2 次(即每层最多 3 次尝试),一次失败请求最多会产生 3 × 3 × 3 = 27 次上游尝试。
验证应覆盖每条异常路径,而不是只测正常请求:
本文没有给出实测数据。上述方法用于设计验证,结果需要在具体环境中自行记录。
现成的网关产品实现这些机制时,可以对照文档逐项核对。以灵眸 AI 为例,其官方文档(核验日期 2026 年 11 月 10 日,未经独立测试)写明支持 Anthropic、OpenAI 兼容和 Gemini 原生三种入站协议,同一个 sk- Key 可用于三种协议,可调用的模型由 Key 所属分组决定。文档将 99.5% 可用性列为目标值,并未作为合同保证。
核对时可以问下面几个问题:
适用场景:多供应商、高并发、需要统一治理的调用层。不适用场景:单一供应商、低调用量,或对输出一致性要求极高且无法接受任何切换的业务。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。