Colly本身是单机爬虫框架,不具原生分布式能力;所谓“分布式”需依赖外部调度层实现任务分发、去重、失败重试与节点健康监控,否则易出现URL重复抓取、任务堆积、限速失控等问题。

Colly 本身不分布式,得靠外部调度层补足
Colly 是单机爬虫框架,NewCollector 实例天然不具备跨进程/跨节点协同能力。所谓“分布式”,本质是把 URL 分发到多个 Colly 进程里跑,靠外部系统管任务分发、去重、失败重试和节点健康。硬把 Colly 当分布式框架用,只会卡在任务重复、节点失联后任务堆积、限速失控这几个点上。
常见错误现象:OnHTML 偶尔不触发、同一 URL 被多个 worker 同时抓、某 worker 挂了之后任务永远卡在队列里。根本原因不是 Colly 写错了,而是没配好上层调度。
- 别在 Colly 回调里直接写入共享变量(比如全局 map),并发下数据竞争不可避免
- URL 入队前必须标准化:用
url.Parse解析后取u.Scheme + "://" + u.Host + u.EscapedPath(),去掉 fragment 和 query 参数(除非业务需要) - 每个 worker 启动时注册 etcd key(如
/workers/hostname-1719872820123),TTL 设为 15 秒,每 5 秒续租一次;调度器监听/workers/目录变更来感知上下线
任务队列选 Redis 还是 Kafka?看失败容忍度
Redis 的 BRPop 简单快,适合日均百万 URL 以内、允许少量任务丢失的场景;Kafka 必须用 acks=all 配置,否则网络抖动时 sarama.SyncProducer 会静默丢消息——这不是 Colly 的问题,是消息投递语义没对齐。
共性陷阱:BRPop 不设超时会永久阻塞,Kafka 消费者没提交 offset 就 panic 会导致重复消费。两者都要加字段:序列化进队列的 JSON 至少含 url、timestamp、retry_count。
立即学习“go语言免费学习笔记(深入)”;
- Redis 方案:任务入队用
LPUSH,worker 用BRPop阻塞取,避免轮询空耗 CPU - Kafka 方案:别只调
producer.Input()<-msg,必须检查producer.Output()返回的 error,并捕获sarama.ProducerError - 无论哪种队列,worker 处理完 URL 后必须先确认完成(del key 或 commit offset),再发下一条
Colly 在多 worker 场景下的限速必须分层
单个 colly.LimitRule 只约束本机请求,并不能防止整个集群 QPS 超限。比如 10 个 worker 各开 Parallelism: 5,实际并发就是 50,远超目标站承受能力。
正确做法是两层限速:节点级用 rate.Limiter 控总 QPS(比如每秒最多 20 请求),域名级再用 colly.LimitRule 控并行数(如 Parallelism: 2)。rate.NewLimiter 实例必须全局复用,不能在 OnRequest 回调里每次 new。
- 随机延迟比固定 Delay 更有效:
Delay: 1 * time.Second, RandomDelay: 500 * time.Millisecond,防被识别为机器流量 - 别把
LimitRule绑定到"*",不同域名响应速度差异大,应按DomainGlob单独配置 - 遇到 429 响应码,立即对该域名 sleep 30 秒,而不是等限流器自然放行
数据怎么从回调安全带出来?别用闭包共享变量
很多人把结果存到包级变量或传指针进回调,结果并发下结构体字段被覆盖、切片 append 错乱、map panic。Colly 回调执行顺序不确定,且可能跨 goroutine。
可靠方式只有一种:用 channel 中转。每个 worker 启动时建一个带缓冲的 chan Result,回调里 resultChan <- result,另起 goroutine 从 channel 拿数据入库或发 HTTP API。缓冲大小建议设为 100–1000,避免 channel 阻塞拖慢采集。
- Result 结构体字段必须全小写(导出需大写),否则 JSON 序列化为空
- channel 发送前做浅拷贝,尤其含 slice 或 map 字段时,避免后续修改污染已发送数据
- 别在
OnHTML里同步调http.Get下载图片——会阻塞 collector,改用c.Visit()异步调度
真实部署时,最难调的不是 Colly 配置,而是 etcd 心跳续租失败导致 worker 被误判下线,或者 Kafka offset 提交延迟引发重复抓取。这些点不写监控指标,光靠日志很难定位。


















