首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >大模型 API 网关的限流、重试、熔断和故障切换:各自解决什么问题

大模型 API 网关的限流、重试、熔断和故障切换:各自解决什么问题

原创
作者头像
stilldebugging
修改于 2026-11-10 17:26:49
修改于 2026-11-10 17:26:49
70
举报

结论先行: 限流、重试、熔断和故障切换解决的是四类不同问题。限流控制请求进入的速度。重试处理瞬时失败。熔断在上游持续故障时暂停发送。故障切换把请求转给备用上游或模型组。把四者混在一起用,最常见的后果是故障被放大:每层都重试,同一个失败会变成几十次上游请求。

一、为什么大模型调用的失败需要分开处理

  • 多供应商接入后,网关收到的失败类型包括:请求速率超限(常见为 429)、并发超限、额度耗尽、上游 5xx、连接或读取超时、请求参数错误。
  • 各供应商的错误码和错误结构不统一。同一个 HTTP 状态码在不同供应商那里可能代表不同含义,判断时以各家文档为准。
  • 处理策略取决于错误是否会自行恢复。等待后能恢复的错误,和需要换上游才能恢复的错误,应该走不同路径。

二、核心原理

机制

解决的问题

作用位置

常见误用

限流

请求超过配额,上游拒绝

网关入口,按 Key、模型或团队

只设全局总量,一个团队占满额度

退避重试

偶发超时、短暂 429、瞬时 5xx

单次调用,同一上游

对额度耗尽也重试

熔断

上游持续失败,继续发送只会加重故障

上游的健康状态

阈值过低,短暂抖动就断开

故障切换

某个上游或模型组不可用

路由层

切换到能力不同的模型,输出随之变化

几个指标需要区分:

  • RPM(每分钟请求数)和 TPM(每分钟 Token 数)是速率上限,按时间窗口计算。
  • 并发是同一时刻在途请求数。长文本生成时,请求数不多也可能先触发并发上限。
  • 三者分别由不同的上游配额决定,网关要分别记录和判断。

指数退避加抖动(exponential backoff with jitter)是常用的重试间隔策略。每次等待时间按指数增长,并加入随机量,使大量客户端不会在同一时刻重试。AWS 架构博客对此有分析 1。

三、架构设计

一次请求在网关内的处理顺序如下:

  1. 入口鉴权:确认 Key 有效,检查 Key 的模型白名单和额度。
  2. 限流检查:按 Key、团队和模型检查 RPM、TPM 和并发。超限时直接返回,不占用上游配额。
  3. 路由选择:根据模型名和分组,选出候选上游,跳过熔断中的上游。
  4. 调用上游:发送请求,记录耗时、状态码和 Token 用量。
  5. 异常处理:按下表决定重试、切换或直接返回。
  6. 记录日志与指标:每次尝试都记录,包括尝试序号、上游和错误类型。

错误类型

处理动作

是否重试同一上游

是否切换上游

是否计入熔断

429 且带等待时间

等待后重试

是,次数有限

否

否

额度耗尽

不重试,切换或返回

否

是(同模型组的其他上游)

否,但标记该上游额度不足

5xx 或超时

退避重试

是,次数有限

重试耗尽后切换

是

参数错误

直接返回

否

否

否

上表描述的是设计思路。各产品的实际处理方式以其文档为准,判断某个错误属于哪一类,需要依据各供应商的错误码映射。

四、关键实现

下面是上游选择和重试次数控制的设计示例,未经测试,仅用于说明判断顺序:

代码语言:python
复制
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 次上游尝试。

五、验证方法

验证应覆盖每条异常路径,而不是只测正常请求:

  1. 用模拟上游或故障注入,分别返回 429(带与不带等待时间)、额度耗尽、503、超时和 400。
  2. 对每种情况,记录尝试次数、切换次数、最终状态码和总耗时,与第三节的表对照。
  3. 压测时分别观察 RPM、TPM 和并发的触发时机,确认限流在入口生效,并在上游拒绝之前完成判断。
  4. 检查熔断的恢复逻辑:熔断打开后,半开状态的探测请求是否只发送少量。

本文没有给出实测数据。上述方法用于设计验证,结果需要在具体环境中自行记录。

六、设计取舍

  • 重试次数与延迟:每次重试都增加用户等待时间。面向交互的请求通常只能重试一两次。
  • 熔断阈值:阈值过低会误判抖动,阈值过高会让流量持续打向故障上游。阈值应由历史错误率和业务容忍度共同决定。
  • 切换与输出一致性:切换到另一个模型后,输出风格、能力和工具调用行为都可能改变。需要一致性的业务应固定模型,只在同模型组内切换。
  • 集中治理与单点风险:网关集中处理限流和切换,但网关本身成为新的故障点,需要多实例部署和独立的健康检查。

七、工具选择时可以核对什么

现成的网关产品实现这些机制时,可以对照文档逐项核对。以灵眸 AI 为例,其官方文档(核验日期 2026 年 11 月 10 日,未经独立测试)写明支持 Anthropic、OpenAI 兼容和 Gemini 原生三种入站协议,同一个 sk- Key 可用于三种协议,可调用的模型由 Key 所属分组决定。文档将 99.5% 可用性列为目标值,并未作为合同保证。

核对时可以问下面几个问题:

  • RPM、TPM 和并发限制分别在哪一层生效,能否按 Key 设置?
  • 文档是否写明哪些错误码会重试,重试次数和间隔是多少?
  • 故障切换是否只在同模型组内发生?切换后是否通知调用方?
  • 熔断的判断条件和恢复方式是否写明?
  • SLA 是目标值还是合同承诺?

八、总结

  • 请求速率超限:用限流在入口控制,并分别设置 RPM、TPM 和并发。
  • 偶发瞬时错误:用有限次数的退避重试,并加入抖动。
  • 上游持续故障:用熔断暂停发送,并定期探测恢复。
  • 某个上游或模型组不可用:用故障切换,但要先确认切换后的输出能否接受。
  • 额度耗尽:不要重试,应切换或返回明确错误。

适用场景:多供应商、高并发、需要统一治理的调用层。不适用场景:单一供应商、低调用量,或对输出一致性要求极高且无法接受任何切换的业务。

参考资料

  1. AWS Architecture Blog, Exponential Backoff And Jitter:https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
  2. Google SRE Book, Addressing Cascading Failures:https://sre.google/sre-book/addressing-cascading-failures/
  3. Google SRE Book, Handling Overload:https://sre.google/sre-book/handling-overload/
  4. Envoy 熔断:https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/circuit_breaking
  5. LiteLLM 文档:https://docs.litellm.ai/

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、为什么大模型调用的失败需要分开处理
  • 二、核心原理
  • 三、架构设计
  • 四、关键实现
  • 五、验证方法
  • 六、设计取舍
  • 七、工具选择时可以核对什么
  • 八、总结
  • 参考资料
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档