限流发生时,先停止继续调用,再把已经拿到的数据落盘并标记完整性,比反复重试更重要。对360搜索的排名查询来说,限流往往只影响后续请求,不影响已返回的那部分结果;真正会毁掉已有结果的,是为了补全而清空旧数据、覆盖同一文件,或把不完整批次当成完整批次继续下游处理。
两种情况的处理方式不同。暂时性限流通常表现为短时间集中请求后连续失败,间隔一段时间后同样的调用又能成功;配额性限流则是在一个周期内稳定失败,换时间点、换参数都难以恢复。
区分依据可以看三点:失败是否集中在某几分钟、失败是否与请求频率同步、降低频率后是否恢复。如果降低频率后恢复,按暂时性限流处理;如果降低频率仍然失败,按配额性限流处理,转成排队和分日执行。
这里有一个容易误判的地方:请求量归零并不等于限流已经解除,也可能是脚本自身报错退出、凭证失效或任务被上游中断。把归零直接当成“可以继续跑”的信号,容易在下一轮再次撞上限流。
这种情况下,已有结果应当原地保留,只对未完成的条目重新发起请求。具体动作是:把本次已成功返回的记录写入独立文件,同时记录这批记录覆盖了哪些查询词、哪个时间点、哪些未完成。
补缺口时不要重跑全量。先读取上次的完成清单,只对缺失项发起调用,并主动把请求间隔拉长。这样做的结果是后续请求量下降,恢复成功的概率提高,同时旧数据不会被新一批结果覆盖。
假设一次任务计划查100个词,限流前成功返回了62个。此时应保留这62条并标注批次不完整,只补38个缺口。如果直接重跑100个词,一方面继续触发限流,另一方面新结果可能覆盖旧结果,导致原本可用的62条也失去可追溯性。
需要保留的元信息包括:抓取时间、查询词、返回状态、是否完整。缺少这些,后续无法判断某条结果是限流前的还是补抓后的,也无法解释两次结果为什么不同。
当降低频率仍然无法恢复时,继续重试只会消耗时间。此时应把任务拆成更小的批次,按可用节奏排队,并冻结当前已经拿到的结果,不再对其做任何覆盖写入。
实施动作可以按下面顺序进行:
这样处理的结果是:即使补抓迟迟不能完成,已有结果仍然可用、可核对;下游也不会因为混入不完整批次而得出错误判断。
常见分歧是:执行者认为“已经查到大部分,可以用”,复核者认为“缺了就是不能用”。把分歧转成可核对的项目,比争论更有用。可以约定一张核对清单,逐项确认:
如果缺失项不影响当前要回答的问题,不完整批次可以用于阶段性观察,但必须标注;如果缺失项正好是判断依据,则应等补抓完成后再下结论。这个界限由使用目的决定,不由数据量多少决定。
多数情况下应保住已有结果,但有一种例外:如果限流期间工具返回结构发生变化,或查询口径本身被调整,旧结果与新结果不可比,此时继续拼接两批数据反而会制造混乱。这时应保留旧结果作为历史记录,另起一个新批次,而不是在旧文件上追加。
判断依据是口径是否一致,而不是数量是否够多。口径一致就补缺口,口径变了就分批次存放。无论哪种选择,都不要在未确认完整性的情况下,把结果直接交给依赖它的下一步流程。