事情本身不复杂,线索都在日志里。接口限流用每分钟 600 次的固定窗口,监控显示整点前后 10 秒内 一半请求收到 429,但这一分钟的总量离 600 还差得远。

第一反应是「窗口起点按本机时间算,多机时钟有偏差」,验证下来不成立。

把日志和配置对完,能解释这个现象的基本就这几处。固定窗口在边界处可放过两倍流量。另一种情况是计数器按实例各算一份,总量被放大。

另外,429 后客户端立刻重试,进一步推高峰值。

第一件事是按秒统计请求量看峰值落在哪

python -c "import json,collections;ts=[json.loads(l)['t'] for l in open('req.jsonl')];print(sorted(collections.Counter(t//1 for t in ts).items())[:5])"

再往下把固定窗口换成滑动窗口或令牌桶

python limiter.py --algo token_bucket --rate 10 --burst 20

限流计数放到共享存储统一口径

python limiter.py --backend redis --key rl:api

给 429 响应补 Retry-After 并让客户端退避

curl -i -X POST https://api.example.com/v1/chat -H 'Authorization: Bearer $KEY' -d '{}'

改完先别撤,确认这几项。整点前后不再出现成片的 429,被拒请求分散到整分钟,同一秒的通过量与配置速率一致。

固定窗口的边界突刺是数学上的必然,流量越集中越明显,换成令牌桶并共享计数才能压住。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。

作者 9823189