限流、配额与并发
网关有两层限流:一层管「你这个账号能用多少」,一层管「这条上游链路还能承接多少」。
两层的错误码都落在 429xx,但成因和处置完全不同。
两层限流
| 用户策略层 | 上游链路层 | |
|---|---|---|
| 限的是 | 你的账号 / 这把 Key | 凭证、模型、厂商三级 |
| 判定时机 | 鉴权之后、路由之前 | 选定上游链路时 |
| 维度 | 并发、累计金额、次数、Token、图片、视频 | 并发、RPM、RPH、RPD、TPM |
| 能否重试 | 看是哪一档,多数等窗口重置 | 可以,网关自己也会先换链路重试 |
| 典型错误码 | 42901 / 42902 / 42905 / 42906 | 42901–42905 / 42908 |
用户策略层
每把 API Key 关联一个限制策略。策略来源有优先级: 生效中的订阅所带的策略优先于 Key 上手动挂载的策略。都没有则不受策略层限制 (但仍要过计费门槛,见 计费、积分与订阅)。
策略包含哪些参数
同时在途的请求数上限。0 表示不限。
累计消费上限,没有时间窗,用完就是用完,不会自动恢复。
这四个维度各自独立,每个都可以配多档窗口,例如「每分钟 60 次 + 每天 5000 次」同时生效。
时间窗是怎么算的
不是自然分钟/自然天,而是以「该维度首次使用的时刻」为锚点向后推。 比如你配了「3600 秒 500 次」,第一次调用发生在 10:17:32,那么这一档的窗口就是 10:17:32 → 11:17:32,到点清零并把锚点顺延。
自然窗口(整点重置)会让所有用户在同一秒集体解禁,制造周期性尖峰。
锚点窗口把每个用户的重置时刻自然打散了。
代价是「什么时候恢复」不能靠看钟推算——所以被拒时请读 Retry-After。
请求次数与 Token 用量共用同一个首次使用锚点;图片与视频各有独立锚点。
被策略层拒绝时的错误码
| 触发的维度 | 错误码 | message |
|---|---|---|
| 并发 | 42901 | concurrency limit exceeded |
| Token 用量 | 42905 | tpm limit exceeded |
| 请求次数 / 图片 / 视频 / 累计金额 | 42902 | rpm limit exceeded |
| 订阅额度用完且未开 API 扣费 | 42906 | 中文文案,见下 |
42902 不一定真的是「每分钟请求数」
请求次数、图片张数、视频数量、累计金额四个维度没有各自专属的错误码,
统一按 42902 返回。别被 rpm limit exceeded 这句英文带偏——
以 Retry-After 和后台「使用情况」页面为准。
订阅用户的额度提示
订阅用户撞上策略窗口时,返回的 42906 带的是中文文案,会说清是哪个维度、哪一档、多久恢复:
{
"code": 42906,
"message": "已达套餐请求次数上限(每 1 小时 500 次),约 1832 秒后自动恢复;如需立即继续可开启API扣费访问",
"error": { "type": "gateway_error", "code": "42906" }
}
只有累计金额这一维度没有恢复时刻,此时文案退化为
订阅额度已用完,可开启API扣费访问继续使用。
并发是怎么占用与释放的
入口预占一个槽位
请求通过鉴权后立即预占,占不到就直接 42901,不进入路由与计费。
请求结束释放
无论成功、失败还是客户端主动断开,收尾都会释放槽位。
漏释放自愈
进程被 kill、宿主机崩溃等极端情况下槽位可能没释放。每个槽位带时间戳, 存活超过 600 秒即被下一次入口校验自动剔除,不需要人工清理。
正常请求远快于此(慢模型实测约 77 秒)。所以「上限 3 却只跑得动 2」这类现象最多持续 10 分钟就会自愈。 如果持续超过 10 分钟,那就不是漏释放,而是真的有请求在途——去查有没有卡住的长连接。
上游链路层
选定上游链路时,网关还会按凭证 / 模型 / 厂商三个粒度分别校验 RPM、RPH、RPD、TPM。 任一粒度超限,这条链路就被跳过。
| 错误码 | 含义 | 恢复 |
|---|---|---|
| 42902 | 分钟级请求数超限 | 下一分钟窗口 |
| 42903 | 小时级请求数超限 | 下一小时窗口 |
| 42904 | 天级请求数超限 | 次日窗口 |
| 42905 | 分钟级 Token 数超限 | 下一分钟窗口 |
| 42908 | 所有可用上游都在限流/失败冷却中 | 临时态,带 Retry-After |
42908 是「链路都在冷却,等等就好」;
50201(no available upstream for this model)是「这个模型压根没有配可用上游」,
等多久都不会好——那是配置问题,请提反馈。
限流响应头
Retry-After: 42
X-RateLimit-Limit-Requests: 60
X-RateLimit-Remaining-Requests: 0
X-RateLimit-Limit-Tokens: 100000
X-RateLimit-Remaining-Tokens: 0
触发限流时两个 Remaining 恒为 0——它们只在被拒时下发,
不能用来做「还剩多少」的实时余量监控。要看余量请用后台的「使用情况」页面。
降低被限流概率
- 先读
Retry-After再重试。不读就退避,多半会撞在同一个窗口上。 - 加抖动。一批客户端同时被拒又同时重试,等于把峰值原样搬到下一秒。
- 控制客户端并发。并发限制是拒绝而不是排队——超了就是
42901,不是等待。 - 批量任务加节流。离线跑批时主动限速,比撞上限再退避高效得多。
- 长文本注意 Token 维度。请求数没超但
42905先到,通常是单次请求太长。
Redis 或配置加载失败时,策略层限流会直接放行并记日志—— 限流故障不应该阻断业务。但计费资格判定相反,是 fail-closed 的: 判不了就拒,避免产生无法计费的调用。