事情本身不复杂,线索都在日志里。网关里配了每秒 50 次的本地限流,上游账号的 TPM 只够每秒 30 次,结果本地放行 50 次、上游回 20 个 429,用户侧大量失败,日志里两类拒绝混在一起。

第一反应是「两类拒绝在日志里没有区分来源」,验证下来不成立。

这类报错背后常见的原因有几处,逐个排除就行。本地阈值按请求数算,上游按 token 算。另一种情况是本地限流没有参考上游的剩余配额。

另外,重试没有区分两类错误,对本地拒绝也做退避。

动手时先把两类拒绝分开打标再统计

python gw.py --tag-limit-source --log-level info

再往下按 token 估算改写本地阈值

python gw.py --limit-by token --tpm 30000

接着读上游返回的剩余配额做动态调整

python gw.py --adapt-from-header x-ratelimit-remaining-tokens

只对上游 429 退避,本地拒绝快速失败

python gw.py --retry-upstream-only

改完先别撤,确认这几项。上游 429 占比降到 1% 以下,本地拒绝能在指标上单独看到,P99 不因重试被抬高。

补一句。两道限流粒度不同,不区分来源就没法判断该扩容还是该放缓,日志里一定要打标记。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。

作者 9823189