4. 元数据采集与同步:抓工具、定策略

我记得刚开始搞数据湖的时候,大家最头疼的不是存储,而是“我东西放哪了?谁碰过?质量怎么样?”元数据采集,说白了就是给数据湖装上一双眼睛。你看不见它,但它什么都知道。

这一章,咱们就聊聊两个主流的抓取工具——Apache Atlas 和 Marquez,以及一个避不开的话题:增量采集。别着急上代码,先理清逻辑。

4.1 为什么需要元数据采集?

你想想看,一个企业级数据湖里,可能有几百上千张表。没有元数据管理,DBA 查个血缘关系得翻半天脚本,分析师找字段定义全靠口口相传。我个人习惯把元数据采集分为三层:

  • 技术元数据:表结构、分区、文件格式、存储路径。
  • 操作元数据:ETL 作业运行时间、数据量变化、失败记录。
  • 业务元数据:字段业务含义、数据质量规则、数据 owner。

采集工具主要解决“技术元数据”和“操作元数据”的自动化抓取。说白了,就是让机器替人干活。

核心观点:元数据采集不是一次性的“搬砖”工作。它必须形成一个闭环——采集 → 存储 → 消费 → 反馈 → 再采集。没有这个循环,你建的数据湖跟一个黑箱子没区别。

4.2 Apache Atlas:企业级元数据治理“重器”

Atlas 是 Hadoop 生态的老牌选手。它支持 Hook 机制,能自动从 Hive、HBase、Sqoop 等组件抓取元数据。我在项目中遇到过最典型的场景:公司有 200 多个 Hive 表,数据工程师离职后没人知道字段怎么来的。Atlas 一上,血缘图自动生成,谁都不好意思再“埋雷”。

4.2.1 架构与采集流程

Atlas 的架构并不复杂,但组件较多。它的核心是“类型系统 + 图存储”。

# 核心组件
- Atlas Server:元数据存储与索引服务(基于 Titan/JanusGraph + Solr)
- Hook:嵌入到 Hive、HDFS 等组件的采集代理
- Import/Export:批量导入导出元数据(如从 Hive Metastore)
- REST API:供外部系统调用

实际抓取时,Hook 监听到 Hive 创建表、修改分区等操作,生成 Kafka 消息。Atlas Server 消费消息,更新 JanusGraph 中的实体和关系。整个过程对用户透明。

一个简单的 Hook 配置示例:

# hive-site.xml 中添加 Atlas Hook
hive.exec.post.hooks=org.apache.atlas.hive.hook.HiveHook
atlas.cluster.name=primary
atlas.rest.address=http://atlas-server:21000

配置好以后,你执行一个 CREATE TABLE,Atlas 自动捕捉。嗯,这里要注意:Hook 对 DDL 操作敏感,但 DML(如 INSERT)默认不采集。如果你需要追踪数据变化,得配合其他工具。

个人经验:Atlas 的 Hook 在集群规模较大时(比如 500+ 节点)会产生不小的网络压力。我的习惯是只对核心业务表启用 Hook,其他表走定时批量导入。这样可以避免采集风暴。

4.2.2 增量采集怎么做的?

Atlas 本身没有“全量 vs 增量”的开关。它的机制是这样的:

  • 实时增量:通过 Hook 监听实时事件(DDL、分区变更),这是最理想的增量模式。
  • 定时批量:利用 Import/Export 工具,比如从 Hive Metastore 导出元数据,然后调用 Atlas REST API 写入。你可以写个脚本,只导出最近 24 小时变化的表。

我曾经踩过一个坑:全量导入 Atlas 后,发现有些表因为血缘关系没刷新,导致数据治理报告不准。后来我改成每天凌晨跑一次增量导入,配合 Hook 的实时推送,才算稳定下来。

# 增量导入脚本示例(简化版)
#!/bin/bash
# 只导出昨天有变更的表
hive -e "SHOW TABLES;" | while read table; do
    mod_time=$(hdfs dfs -stat "%Y-%m-%d" /user/hive/warehouse/$table)
    if [[ "$mod_time" == "$(date -d 'yesterday' '+%Y-%m-%d')" ]]; then
        ./atlas-import.sh --table $table
    fi
done

警告:Atlas 的 Import 工具默认是追加模式,不会自动删除已删除表的元数据。你需要额外写一个清理逻辑,否则元数据仓库里会堆积大量“死”资源。

4.3 Marquez:轻量级血缘追踪利器

跟 Atlas 的“重”不同,Marquez 走的是另一种路线。它专注于“数据集血缘 + 作业运行元数据”,更偏向操作元数据。我是在做实时数据湖项目时接触它的。当时团队嫌弃 Atlas 太重,Marquez 的简单 API 和轻量部署让我们眼前一亮。

4.3.1 核心设计

Marquez 只有一个核心服务,依赖 Postgres 或 MySQL 做存储。它不提供 UI 界面(有单独的 Web 端),主要通过 REST API 交互。采集方式也比 Atlas 灵活——你可以通过编程调用 API,也可以接入 OpenLineage 协议。

说白了,Marquez 更像一个“元数据接收器”,由上游工具(如 Spark、Airflow、dbt)主动推送元数据。你不用操心 Hook 冲突或版本兼容。

# 通过 OpenLineage 向 Marquez 推送一条作业运行记录
POST http://marquez:5000/api/v1/lineage
{
  "eventType": "COMPLETE",
  "job": {
    "namespace": "my-namespace",
    "name": "etl_daily_order"
  },
  "inputs": [{
    "namespace": "hdfs",
    "name": "/data/orders/raw"
  }],
  "outputs": [{
    "namespace": "hdfs",
    "name": "/data/orders/clean"
  }],
  "run": {
    "runId": "run-uuid-123"
  }
}

这个 API 调用非常简单。你用任意语言封装一下,就能把 ETL 作业的上下游关系记录得一清二楚。

关键区别:Atlas 主动抓(Push),Marquez 被动收(Pull + Push 混合)。如果你们的作业编排工具已经支持 OpenLineage,Marquez 几乎是开箱即用。

4.3.2 增量采集策略

Marquez 的增量采集天然存在。因为每次作业运行都会生成一个带有 runId 的事件。你只需要在 API 请求中带上时间戳或版本号,Marquez 内部会根据 runId 去重。我个人的习惯是:

  • 对于定时 ETL 作业,每次运行都推送一条完整事件,Marquez 会自动覆盖旧版本(根据 runId 更新)。
  • 对于实时流作业(比如 Kafka → Flink → HDFS),我推荐每个微批次推送一次,但带上批次时间戳。Marquez 的 API 支持按时间范围查询,这样你只拉取最近 N 小时的增量元数据。
# 按时间范围查询增量元数据
GET http://marquez:5000/api/v1/lineage?since=2025-03-01T00:00:00Z&until=2025-03-02T00:00:00Z

Marquez 没有全量导入的概念。它的设计初衷就是“持续流入,按需查询”。如果你想迁移数据,只能通过 API 一条条重播。嗯,这里没有捷径。

避坑指南:我曾经用 Marquez 做一个实时数据湖项目,发现当作业频率很高(每分钟一次)时,Postgres 成了瓶颈。解决方案是给 lineage_events 表加分区,并按天清理 30 天前的历史记录。Marquez 本身不提供自动清理,你得写个定时 SQL。

4.4 Atlas vs Marquez:如何选型?

很多同学问我这两个工具哪个好。我的回答是:没有最好,只有最合适。下面这张表是我根据实际项目经验整理的对比:

维度 Apache Atlas Marquez
部署复杂度 重(依赖 HBase/Solr/JanusGraph) 轻(仅需一个 JAR + 数据库)
增量采集能力 基于 Hook 的实时增量 + 定时批量导入 基于作业事件的天然增量(每条事件独立)
血缘粒度 字段级别(表级、列级) 数据集级别(表/文件级)
生态集成 原生支持 Hive/HBase/Sqoop 等 OpenLineage 协议(Spark/Airflow/dbt 等)
UI 与可视化 自带管理界面,血缘图可交互 需单独部署 Web 端或接 Grafana
适用场景 传统 Hadoop 湖、强治理需求 现代数据湖、实时流、轻量需求

看到这你可能会想:“我能不能两个都要?”我试过。在同一个项目里,用 Atlas 管理技术元数据(表结构、Hive 分区),用 Marquez 追踪作业血缘。两者之间通过 API 同步核心信息。但代价是运维成本翻倍。如果你团队人力有限,我建议只选一个,把增量采集做深做透。

4.5 增量采集策略的核心要点

不管用 Atlas 还是 Marquez,增量采集共同要面对三个问题。我把它总结成一张思维导图:

增量采集策略核心要点 增量采集策略 数据变更检测 时间戳对比 事件订阅 去重与幂等性 唯一标识 版本号控制 存储与定期清理 分区策略 TTL过期删除 实战建议 三者缺一不可:只做检测不做去重 → 数据冗余;只做去重不做清理 → 存储爆炸

简单总结一下增量采集的核心三要素:

  1. 数据变更检测:靠时间戳对比还是事件订阅?我推荐两种都支持。如果你的源系统有 CDC(变化数据捕获),优先用事件。否则,时间戳配合轮询更可靠。
  2. 去重与幂等性:同一个元数据事件被重复推送怎么办?必须给每个实体分配唯一 ID,并在存储层做 upsert。Atlas 通过 GUID,Marquez 通过 runId,都是这个道理。
  3. 存储与定期清理:增量数据积累一个月后,元数据仓库可能膨胀一倍。我一般在 Postgres 里按天分区,再用 crontab 删除 60 天前的分区。Atlas 的 JanusGraph 里,可以用 Solr 的 TTL 机制。

重要:增量采集不是万能的。初次部署时,你仍然需要一次全量导入来“初始化”元数据。我的建议是:先跑一次全量,然后用增量持续补充。全量导入的脚本要保留,以便数据湖重建或迁移时复用。