if resp.status_code == 429:
    wait = int(resp.headers.get('Retry-After', '1'))
    time.sleep(wait + random.random())

上游限流返回 429,响应头里 Retry-After 写着 2,客户端代码没读这个头,失败后立刻重试,一秒内打了 40 次,配额从每分钟 100 掉到 20。这类现象通常不是突然出现的,往前翻半天日志能看到苗头。

追下去是这么回事:重试逻辑只判断了状态码非 2xx,没有区分 429 和其他错误,也没有退避。限流窗口是滑动统计的,越重试占用的配额越多,恢复时间被不断往后推。

「429 重试」确认了原因之后,改动尽量只碰那一处,顺手改的东西后面最容易出问题。监控和日志的时间要对上,时区不一致会多绕很大一圈。

临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。

处理上按这个顺序:429 单独处理 读取 Retry-After 按这个秒数等待;没有 Retry-After 时用指数退避加随机抖动;重试次数设上限 超过就把请求放进队列或直接失败;把 429 计入监控 连续出现就通知调用方而不是继续重试。

确认没问题再收工,触发限流后客户端按秒级间隔重试 429 次数明显下降 配额能在下一分钟恢复正常。

作者 9823189