结论先说:如果限流只影响尚未返回的请求,而已经拿到的结果能完整落盘并带有可追溯的记录,那么优先保住已有结果、暂停新调用,比立刻换IP或加并发更稳妥;反过来,如果已有结果与后续结果必须拼成一个整体才有意义,那么保住的只是半成品,应先判断缺失部分能否独立重跑,再决定是否继续。
脚本调用工具时,限流通常出现在两类位置:一类是请求发出后没有响应,另一类是响应返回了一部分字段。前者不会污染已有结果,后者可能让同一批数据里混入不完整记录。判断依据不是“拿到了多少条”,而是每条记录是否自带完成标记。
一个实际动作是:在限流发生后,先停止新请求,把内存中未写入的响应立即追加到本地文件,并记录最后一条成功响应的标识。这个动作的结果会直接决定下一步——如果落盘完整,下一步是安排补跑;如果落盘不完整,下一步是回退到上一个稳定断点,而不是继续重试。
很多脚本在收到限流信号后会立刻做三件事:换代理、提高重试次数、把并发调低后继续跑。这三件事在不同前提下效果相反。
换代理只有在限流按来源地址计数时才可能有效;如果限流按账号、令牌或调用配额计算,换地址不会改变结果,反而会让日志里出现多个来源,增加后续对账难度。提高重试次数在没有退避间隔时只会加剧限流,并且让已有结果的边界变得模糊。调低并发继续跑,如果脚本本身没有断点续传,等于重新开始,已有结果可能被覆盖。
一个可区分的证据是:查看返回内容里是否带有重置时间或剩余配额字段。如果有,说明限流是配额型,等待窗口结束再继续比换地址更合理;如果没有,只返回一个通用错误,则更可能是频率型,需要降低请求速率并保留已有结果。
保护已有结果的关键不是备份整份输出,而是维护一个轻量的断点文件。它至少记录:最后成功的请求参数、最后成功的时间、已写入结果的文件名或分片编号。这样即使脚本被中断,也能从断点继续,而不是从头开始。
假设一个场景:脚本需要按批次拉取一千条记录,每批一百条,跑到第六批时被限流。如果断点文件记录了“第五批已完成”,那么恢复时从第六批开始即可;如果没有断点文件,只保存了前五百条结果,恢复时要么重复拉取前五批,要么无法确定从哪里接上。这个例子里数字只用于说明比较方法,实际批次大小需要按工具响应和本地存储情况调整。
需要说明的是,断点文件本身也可能写入失败。因此更稳妥的做法是先写临时文件,确认写入成功后再替换正式断点。这个动作的结果是:即使进程在写入过程中被终止,断点也不会指向一个不存在的结果文件。
反例是:已有结果和后续结果之间存在强一致性要求,单独使用已有结果会得出错误判断。例如结果是一组相互关联的记录,缺失其中一部分后,剩余部分的汇总值会偏低,而脚本又无法标记哪些记录缺失。此时保住已有结果并不能保护决策,反而可能让人误以为数据完整。
判断条件在于:结果是否带有“缺失标记”。如果每条记录都能标注“未获取”或“待补”,那么已有结果可以保留并继续补跑;如果结果格式不允许标记缺失,那么正确做法是丢弃这批不完整结果,回到上一个完整批次,而不是保留半成品。
另一个会使结论失效的情况是:限流信号来自工具方的策略变更,而不是临时频率超限。此时等待和补跑都可能无效,需要先确认调用方式是否仍然被支持。具体工具的当前限制和调用方式属于会变化的信息,应以工具方最新说明为准,不能凭旧脚本的默认值推断。
把处理顺序固定下来,可以减少限流带来的损失:第一步,收到限流信号后立即停止新请求,把内存中的响应写入本地;第二步,检查断点文件和结果文件的完整性,确认最后一条成功记录;第三步,根据返回内容判断限流类型,再决定是等待、降速还是调整调用方式;第四步,只有在断点可恢复且结果允许缺失标记时,才继续补跑。
这个顺序的结果是:已有结果被固定下来,后续决策基于确定的数据边界,而不是基于“大概拿到了多少”。如果第二步发现断点不可信,那么下一步应是回退到上一个完整批次,而不是继续在当前批次上重试。