Colly应作为独立采集子服务,通过HTTP或消息队列与主服务解耦;禁止在回调中直连DB或调用API,只做结构化提取并发送至Kafka或channel,配合sync.Pool复用body切片、WriteAPI异步写入InfluxDB及定制Prometheus buckets。

用 Colly 做数据采集入口,但别直接扔进微服务主逻辑
Colly 本身不是微服务组件,它只是个爬虫框架;硬塞进业务服务里会导致职责混乱、资源争抢、启动变慢。正确做法是把它做成独立的采集子服务,通过 HTTP 或消息队列与主服务解耦。
常见错误现象:panic: runtime error: invalid memory address 往往出现在 Colly 回调里直接调用未初始化的 DB client 或未加 context 控制的 long-running goroutine。
- 采集服务应有自己的
main()入口,独立监听配置变更(如种子 URL 列表从 etcd 加载) - 所有 Colly 的
OnHTML、OnRequest回调里禁止直接写数据库或调用外部 API,只做结构化提取 + 发送到本地 channel 或 Kafka topic - 用
sync.Pool复用colly.Response中的 body 字节切片,避免高频 GC
InfluxDB 写入必须用 WriteAPIBlocking 还是 WriteAPI?
取决于你对可靠性 vs 吞吐量的取舍。WriteAPIBlocking 是同步阻塞调用,每条数据都等服务确认;WriteAPI 是异步批量写入,性能高但可能丢数据。
真实场景中,90% 的时序采集服务应该用 WriteAPI,配合手动 flush 和错误重试机制,而不是依赖 Blocking 模式。
立即学习“go语言免费学习笔记(深入)”;
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
-
WriteAPIBlocking适合调试、单点验证或低频关键指标(如告警开关状态) -
WriteAPI必须设置writeAPI.FlushInterval(1 * time.Second),否则 buffer 可能积压数秒才发 - 写入失败时,
writeAPI.Error()返回的是非空 error,但不会中断后续写入 —— 需主动轮询并记录 - 批量写入时,
NewPointWithMeasurement的 tag key 不建议用动态字段(如"user_id_" + userID),会爆炸性增加 series cardinality
Gin 中间件采集指标时,Histogram 的 buckets 怎么设才不翻车
默认的 promhttp Histogram buckets 是 [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10] 秒,对微服务完全不合适 —— 你的 P99 响应时间大概率在 50~200ms 区间,全落在第一个 bucket 里,毫无区分度。
真正有效的做法是按服务 SLA 定制 buckets,比如你承诺 99% 请求 ≤ 200ms,那就把 bucket 设成 []float64{0.05, 0.1, 0.15, 0.2, 0.3, 0.5}(单位:秒)。
- 不要复用全局 registry,每个服务用
prometheus.NewRegistry()隔离指标命名空间 - 在 Gin 中间件里用
defer+time.Since()记录耗时,避免被 panic 中断导致未 Observe - HTTP 状态码作为 label 时,用
strconv.FormatUint(uint64(status), 10)而不是直接拼字符串,防止 label 值含非法字符
go-zero 里嵌入采集逻辑,最容易被忽略的并发陷阱
go-zero 默认的 Run() 启动方式会接管整个进程生命周期,如果你在 logic 层里起 goroutine 拉取第三方 API 数据,很容易变成“孤儿 goroutine” —— 主服务退出时它们还在跑,且无法被 context.cancel 捕获。
真正安全的做法是把采集任务注册为 go-zero 的 service.AddShutdownCallback(),并在 callback 里显式 cancel 所有采集 goroutine。
- 所有采集定时器(
time.Ticker)必须绑定到 service 的ctx,不能用context.Background() - go-zero 的
rpcx.Client和redis.NewRedis实例自带连接池,但采集模块如果自己 new http.Client,必须手动设Transport.MaxIdleConnsPerHost = 100 - 用
svc.svcCtx传参比全局变量更可靠,尤其在多实例部署时,避免不同服务实例污染同一变量
Colly 的回调、InfluxDB 的写入模式、Prometheus 的 bucket 设置、go-zero 的生命周期管理 —— 这四点不细抠,系统上线后监控看不出来问题,但一到高峰就 silently fail。


















