返回博客

大规模数据采集的稳定性:扩量之后才会暴露的几类问题

采集任务从十个目标扩到上千个,崩掉的通常不是解析逻辑。失败分类与去重、限速与并发、断点续跑、出口失效处理、一致性校验和几个关键监控指标,都是规模化之后才会暴露的问题。

一个采集脚本在十个目标上跑得顺,扩到上千个就开始掉成功率。加过重试、换过代理、调过并发,问题还是反复出现。往下查,卡住的往往不是解析逻辑,而是没搭起来的那几层工程。下面这些事在小规模的时候根本不会出现。

失败先分类,重试才有意义

采集必然有失败。关键在于是不是把失败分了型:网络抖动和连接重置可以立刻重试;临时限流要退避之后重试;页面结构变化导致解析结果为空,重试一万次也没用,该记录并告警;目标本来就不存在,标记完成就行,不要再来;环境或出口起不来,换一个再试。

一律重试是最容易犯的错。它会把需要人工介入的问题用循环盖住,同时白耗配额和出口。退避也要做,重试间隔递增,不然一批任务会在同一个时间窗口里集中打回去,反而把限流打得更狠。

重试往下一层就牵出去重。一次任务可能因为重试被执行多遍,所以每个任务要有稳定的唯一标识——比如 URL 规范化之后的值——落库时按这个标识做幂等写入。否则重试越多,脏数据越多。

限速和并发是两件事

并发数往上加,吞吐不一定跟着涨。同时有三个约束在起作用:目标站点能承受多少(超了触发限流,总吞吐反而下降)、本机的内存与 CPU、以及单个环境或会话能不能同时跑多个任务。

比较稳的做法是从低并发起步逐步加压,把成功率和响应时间一起画出来,找那个明显变差的拐点。限速是另一件事,它控的是对同一个目标的访问节奏,跟全局并发数不是一回事。一批任务分散打多个站点时,每个站点的节奏要分开定。

断点续跑靠状态持久化

任务跑几个小时中断一次很正常,从头再来一遍的成本很难接受。条件是状态要落盘:待处理、处理中、已完成,再加上重试次数、下次可执行时间、错误类型。进程启动时从存储里读回队列,而不是从内存里重建。

只在内存里维护队列,是最常见的看起来能跑的写法。进程一挂,排队中的任务全部丢失,账也对不上。

代理和出口的失效要单独处理

出口被目标封掉、代理掉线、地区节点漂移,这些在规模化之后会持续发生,不是异常而是常态。把出口当成可替换的资源来处理:任务失败时先判断是目标限流还是出口不可用,前者退避,后者换出口重试;同时记录每个出口的失效率,把明显变差的一批摘出去。

反过来,如果所有任务共用一条出口,一个任务把链路打崩,后面全部受影响,排查起来还要从日志里倒推是哪一条。

数据一致性校验

跑通不等于数据对。落库之后要能回答几个问题:任务完成数和落库行数能不能对上、解析结果为空的比例是多少、关键字段的缺失率有没有异常抬头、重复行有多少。

这类校验不用做得复杂,按批次抽查即可,但必须有人看结果。规模大了以后,错误的数据比没有数据更麻烦。

监控盯哪几个

指标不要贪多,能反映系统健康状态的几个就够。

  • 成功率,以及失败类型的分布,看是哪一类错误在涨
  • 任务队列长度和平均等待时间,积压持续变长说明入口和出口不匹配
  • 活跃环境数和相关进程数,长时间单向增长通常意味着回收有泄漏
  • 单位时间产出量,用来判断吞吐是不是被限流压住了
  • 出口失效率,决定要不要换一批节点

几个指标里只要有一个长时间单向变化,先查回收和重试这两处逻辑。

环境层要独立出来

把这些放在一起看,会得到同一个结论:环境层得独立于脚本管理。环境池化要求环境能被集中调度,而不是散落在各个脚本里;资源回收要求状态可查询,而不是靠脚本自己兜底;换环境重试、换出口重试这些动作,只有在环境可以独立调度时才成立。

脚本只管逻辑,环境层管资源和身份。PurpleMark 在这类架构里承担的就是这一层,提供可批量创建、可绑定独立网络出口、状态可查询的环境资源。

合规边界

规模化能力不等于可以随意采集。遵守目标站点的 robots 协议和服务条款,不采集个人信息,不绕过技术保护措施,控制请求频率不要影响对方服务的正常运行。稳定性是技术问题,能不能采是另一个问题,两边都要过。