事情本身不复杂,线索都在日志里。接口限流用每分钟 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,被拒请求分散到整分钟,同一秒的通过量与配置速率一致。
固定窗口的边界突刺是数学上的必然,流量越集中越明显,换成令牌桶并共享计数才能压住。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。
