遇到限流时,最需要保护的不是“继续跑完”,而是已经拿到的结果和已经消耗掉的任务进度。我的建议是:先暂停新请求,把已落地的数据固定成可恢复的快照,再用分批、退避和断点续跑把剩余任务接上。下面用一个假设情境把取舍讲清楚。
假设你用一套脚本调用百度推广相关的查询工具,任务是拉取一批关键词的展现、点击和消费数据,共 2000 条。脚本跑到第 700 条时开始大量返回失败或超时,日志里出现“请求过于频繁”“访问受限”之类的提示。此时你手上已有 700 条结果,其中一部分可能只是部分字段,剩余 1300 条还没开始或刚开始。
这时最常见的两种做法是:做法 A,立即重试直到成功;做法 B,先停下,把已有结果落盘并记录断点,再决定后续节奏。两者都合理,但适用条件不同。A 适合失败是偶发、单次重试就能恢复、且任务量很小的情况;B 适合失败集中出现、连续多次失败、任务量大、数据有时效要求的情况。限流场景通常更接近后者,因为连续失败说明限流不是偶然抖动,继续重试只会让更多请求撞在同一堵墙上。
在决定保护动作之前,先区分原因,因为不同原因对应不同代价。可以从这几个可观察的证据入手:
这里有一个容易误判的点:请求量归零或抓取量突然下降,本身不能证明你处理正确。它也可能是脚本崩溃、任务队列为空、上游数据源本身没有更新,或者你主动停下的结果。所以不要把“没报错”当成“限流已解决”,要看恢复后的成功率和数据完整性。
无论最终选 A 还是 B,第一步都应该是固定已有结果,因为它是你唯一确定不会丢的资产。可以按下面的顺序做:
做完这些,你已经把“限流造成的损失”限制在剩余任务上,而不是全部重来。这一步的代价是几分钟的整理时间,收益是避免重复消耗配额和重复请求。
选做法 A(立即重试)的条件:任务量小、失败是偶发、单次重试成功率高、数据时效性极强且不能等。代价是可能加剧限流,导致原本能成功的请求也失败,甚至触发更长的冷却期。如果重试两三次仍失败,就应该切换到做法 B,而不是继续硬试。
选做法 B(先停后跑)的条件:失败集中出现、任务量大、数据可以分批交付、你希望保留可恢复的进度。代价是需要额外写断点续跑逻辑,交付时间会拉长。具体做法包括:
一个可操作的判断方法是:先小批量试跑。取剩余任务中的 20 到 50 条,用降低后的频率跑一遍,记录成功率和耗时。如果成功率高,再按这个节奏放大批量;如果仍然失败,说明限流还没解除或参数不对,继续等待和排查,而不是扩大请求。
限流解除、脚本续跑完成后,不要直接交付。至少做三件事:核对总条数与预期是否一致;检查“部分字段”的条目是否已补齐;对比断点前后的数据口径是否一致,例如时间范围、筛选条件有没有在恢复时被改动。如果口径变了,前后数据不能直接拼接,需要重新拉取受影响的区间。
最后提醒一点:不同工具对频率、配额和失败返回的表述不一样,具体限制需要以你实际使用的工具说明和返回信息为准。脚本能做的,是在不确定的限制下,把已经拿到的结果保护好,把剩余任务变成可恢复、可验证的进度,而不是赌一次重试就能全部跑完。