以下页面描述网关的预期行为。开源版本与企业版本正在拆分中,首个正式版本发布后细节会同步更新。
熔断
失败的目标如何被暂停轮转、如何被重新探测、如何回到服务。
一个持续失败的目标,每次被选中都要消耗一个请求。熔断把它从轮转中摘出去, 直到有证据表明它又能服务了。
失败分类
每次失败的尝试都会先被分类,再决定动作。当 provider 提供了自己的错误码、类型或异常名时, 分类以它为准;只有在拿不到这些信息时,才依据状态码判断。
| 分类 | 重试 | 暂停轮转 | 含义 |
|---|---|---|---|
| 瞬时故障 | 同一 target,退避重试 | 否 | 网络错误,或未报告限流的 5xx |
| 触发限流 | 换用其他密钥 | 是,时间较短 | 该密钥或该模型被限流 |
| 凭据被拒绝 | 换用其他密钥,不退避 | 是 | 密钥本身被拒绝 |
| 配额用尽 | 换用其他密钥,不退避 | 是 | 账号余额耗尽或超出上限 |
| 无该模型权限 | 换用其他密钥,不退避 | 是,仅该模型 | 该密钥访问不了所请求的模型 |
| 模型已退役 | 换用其他密钥,不退避 | 是,仅该模型 | provider 已下线该模型 |
| 地区被封 | 换用其他密钥,不退避 | 是,仅该模型 | provider 拒绝请求来源地区 |
| 请求被上游拒绝 | 否 | 否 | 问题出在请求本身 |
| 无法识别 | 否 | 否 | 没有可用于决策的信号 |
其中最关键的一条规则:只有当失败说明了这个 target 自身有问题时,才会把账算在它头上。 一个畸形请求永远不会让健康的 target 被暂停轮转 —— 否则一个乱发请求的调用方就能让某个 provider 对所有人不可用。
暂停的范围
暂停范围会按失败本身能支持的范围尽可能收窄:
- 凭据被拒绝 → 暂停整个密钥(对它的所有模型)
- 模型不可用 → 只暂停该模型,密钥继续服务其他模型
暂停多久
等待时长按阶梯增长:从一个较短的值开始,每次探测失败后翻倍,直到该分类对应的上限。
如果 provider 自己给了等待时长(Retry-After Header,或错误体里的结构化重试提示),
则以它为准,但设有一个下限,避免 provider 给出不到一秒的提示时被每秒重试一次。
等待时长带有抖动,避免整个集群在同一时刻去探测同一个 target。
重新探测
等待结束后,该 target 进入 due 状态。此时只放一个请求过去,其他请求继续跳过它, 直到这次探测返回结果。
| 探测结果 | 处理 |
|---|---|
| 服务成功 | 解除暂停,按渐进方式恢复流量,而不是立刻回到满权重 |
| 同样的拒绝 | 继续暂停,阶梯上升一级 |
| 不同的失败 | 单独记录;本次暂停予以结算 |
网络错误或 5xx |
在同一级重新暂停,因为这个回答没有说明 target 有问题 |
手动解除
可以通过 API 或面板手动解除暂停。target 立即回到轮转,并重新开始渐进恢复。
编辑凭据同样会解除它的暂停状态 —— 理由是 provider 之前的回答针对的是改动前的值。