4. 元数据采集策略:主动采集 vs 被动采集、增量采集 vs 全量采集、采集频率设计

元数据采集是整个监控体系的「水源」。水源不干净,后面所有工作都是白费。我见过太多团队在采集阶段就埋了坑,后面排查问题时才发现——原来数据根本没采上来,或者采上来的全是错的。

这一章,咱们把采集策略拆开揉碎了讲。说白了就三个核心问题:谁来触发采集?采多少?多久采一次?

4.1 主动采集 vs 被动采集:谁先动手?

这是采集模式的第一道选择题。我个人的习惯是:先看数据源是否可控,再决定用哪种。

对比维度 主动采集(Pull) 被动采集(Push)
触发方 采集系统主动请求 数据源主动上报
典型场景 爬取数据库元数据、扫描文件系统 数据变更事件、日志推送
实时性 取决于轮询间隔 接近实时
对源系统影响 有查询压力,需控制频率 需在源端安装Agent或Hook
实现复杂度 较低,调度器+连接器即可 较高,需处理协议、认证、重连

我的经验法则:

  • 内部系统(如自建Hive、MySQL)→ 优先主动采集,可控且简单
  • 外部系统(如SaaS工具、第三方平台)→ 只能用被动采集,人家不给你开查询接口
  • 核心业务系统(如交易库)→ 必须被动采集,主动轮询可能把库查挂

我曾经在一个金融项目里吃过亏。当时对核心交易库用了主动采集,每5分钟扫一次表结构。结果某次大促期间,采集脚本和业务查询撞在了一起,数据库连接池被打满。嗯,从那以后,凡是标注了「核心」的系统,我都强制要求用被动采集。

4.1.1 主动采集的实现要点

主动采集的核心是连接器(Connector)。每个数据源类型都需要一个专门的连接器。我一般这样设计:

// 伪代码:主动采集调度器
class MetadataCollector {
    schedule = {
        "hive_metastore": "0 0 */2 * * ?",   // 每2小时
        "mysql_500": "0 */30 * * * ?",       // 每30分钟
        "hdfs_namenode": "0 0 3 * * ?"       // 每天凌晨3点
    }
    
    function collect(sourceType, endpoint) {
        connector = ConnectorFactory.create(sourceType)
        connector.connect(endpoint)
        metadata = connector.extract()
        // 校验完整性
        if (validate(metadata)) {
            saveToStore(metadata)
        } else {
            alert("采集数据校验失败: " + sourceType)
        }
    }
}

小技巧:主动采集一定要加「熔断机制」。如果连续3次采集失败,自动暂停该数据源的采集任务,并通知值班人员。别让一个坏掉的数据源拖垮整个采集集群。

4.1.2 被动采集的实现要点

被动采集通常需要你在数据源侧部署一个轻量级Agent,或者利用数据源自带的变更捕获机制(比如MySQL的Binlog、Kafka的Connect)。

我推荐的做法是:

  • 事件标准化:所有被动采集的事件,统一转换成标准格式({eventType, source, timestamp, payload})
  • 缓冲队列:用Kafka或RocketMQ做缓冲,防止采集端处理不过来导致数据丢失
  • 去重机制:网络抖动可能导致重复推送,消费端要做幂等处理

注意:被动采集最怕「断连」。我曾经遇到过一个Kafka Connect任务挂了三天没人发现,三天内的元数据变更全部丢失。后来我强制要求:所有被动采集通道必须有心跳检测,超过5分钟无心跳就告警。

4.2 增量采集 vs 全量采集:采多少?

这个问题其实没有标准答案。我的判断依据是:数据量有多大?变更频率有多高?

采集方式 适用场景 优点 缺点
全量采集 首次接入、数据量小、结构稳定 实现简单,数据完整 耗时长,对源系统压力大
增量采集 日常维护、数据量大、频繁变更 效率高,负载低 需维护状态,可能遗漏

你想想看,一个PB级的数据湖,每天全量采集一次?不现实。但一个只有几百张表的MySQL实例,全量采集也就几秒钟,何必折腾增量呢?

4.2.1 增量采集的三种常见模式

我个人在实践中总结出三种增量模式,你可以根据场景选:

  1. 时间戳模式:记录上次采集时间,只采集修改时间大于该时间的数据。最简单,但依赖数据源有可靠的修改时间字段。
  2. 版本号模式:数据源维护一个递增的版本号,采集时只拉取版本号大于上次记录的。适合有版本管理的数据源(如Git、Hive的Schema Registry)。
  3. 事件日志模式:通过监听变更事件(如Binlog、Audit Log)来捕获增量。实时性最好,但实现最复杂。

避坑指南:我曾经用时间戳模式采集一个Oracle数据库,结果发现DBA在凌晨做了数据迁移,所有表的修改时间都被更新了。第二天增量采集把全库又拉了一遍,直接把网络打爆。后来我加了「变更量阈值检测」——如果本次增量采集的数据量超过正常值的3倍,自动暂停并人工确认。

4.2.2 全量+增量的混合策略

这是我在生产环境中用得最多的方案。说白了就是:

  • 首次接入:全量采集一次,建立基线
  • 日常运行:增量采集,只拉变化的部分
  • 定期对账:每周或每月做一次全量采集,和增量结果做比对,修复遗漏

这个策略的好处是:既保证了日常效率,又通过定期对账兜底,防止增量采集漏掉数据。

4.3 采集频率设计:多久采一次?

频率设计是门平衡的艺术。采得太频繁,源系统扛不住;采得太少,元数据滞后,监控失去意义。

我一般按数据源的「变更剧烈程度」来分级:

变更等级 典型数据源 建议采集频率 说明
S级(高频变更) 实时数仓、Kafka Topic 1-5分钟 表结构可能随时变化,需快速感知
A级(日常变更) 业务MySQL、Hive分区 30分钟-2小时 大部分变更发生在工作时段
B级(低频变更) HDFS目录、静态文件 每天1-2次 结构基本固定,偶尔调整
C级(几乎不变) 维度表、码表 每周1次 变更极少,甚至手动触发即可

我的习惯:频率设计不要「一刀切」。同一个集群里的不同表,频率可以不一样。比如订单表每10分钟采一次,而地区码表每天采一次就够了。在采集配置里加一个「frequency_override」字段,允许针对特定表单独设置频率。

4.3.1 频率设计的三个约束条件

定频率之前,先问自己三个问题:

  1. 源系统能扛住吗?——采集对源系统的CPU、IO、连接数影响有多大?压测一下再定。
  2. 采集窗口够用吗?——一次全量采集需要10分钟,你设了5分钟一次,那永远采不完。
  3. 业务容忍度多高?——元数据变更后,业务多久能接受延迟?决定了你的最大间隔。

我曾经遇到一个案例:某团队把Hive Metastore的采集频率设成了1分钟一次,结果Metastore的连接数被打满,所有Hive查询都报错。后来我帮他们改成「变更事件触发+5分钟兜底轮询」,问题才解决。

4.4 整体策略框架

说了这么多,咱们用一张图把整个采集策略串起来。下面是我在实际项目中常用的决策框架:

元数据采集策略决策框架 数据源接入 主动采集(Pull) 被动采集(Push) 全量采集 增量采集 全量采集 增量采集 低频 每天/每周 中频 30分钟-2小时 低频 每天/每周 高频 1-5分钟 决策要点 1. 可控的内部系统 → 主动采集 + 增量为主 + 定期全量对账 2. 不可控的外部系统 → 被动采集 + 事件驱动 + 缓冲队列 3. 核心业务系统 → 被动采集 + 高频增量 + 熔断保护 4. 低频静态数据 → 主动采集 + 全量 + 低频轮询

这张图基本概括了我做采集策略设计的思路。你从数据源接入开始,先判断用主动还是被动,再决定采全量还是增量,最后定频率。每个分支都有对应的典型场景。

总结一下我的核心建议:

  • 别追求「实时」,先保证「准确」。一个每天准时跑一次的准确采集,比一个每5分钟跑但经常丢数据的采集有用得多。
  • 采集策略要「可调」。上线后根据实际运行数据(采集耗时、源系统负载、数据遗漏率)持续优化频率和模式。
  • 永远要有「兜底」。增量采集再高效,也得定期全量对账。这是我在多次踩坑后得出的铁律。