3. 元数据采集技术:JDBC/ODBC采集、日志解析采集、API采集、事件监听采集

元数据采集,说白了就是怎么把数据从各个源头“捞”出来。我做了这么多年数据治理,见过太多团队在采集这一步就栽了跟头——要么漏采了关键信息,要么把源库压垮了。今天咱们就把四种主流采集方式掰开揉碎讲清楚。

3.1 JDBC/ODBC采集:最传统,也最稳

JDBC和ODBC是数据库连接的标准接口。这种方式适合采集结构化元数据,比如表结构、字段信息、主键、索引这些。

工作原理:通过数据库驱动直连,执行系统表或信息视图的查询。比如MySQL的information_schema,Oracle的ALL_TAB_COLUMNS。

核心优势:

  • 兼容性好——几乎所有关系型数据库都支持
  • 实时性强——查的就是当前状态
  • 实现简单——写几条SQL就能跑起来

但我得提醒你,这种方式有个大坑。我在项目中遇到过,直接用JDBC去扫几百张表的元数据,结果把生产库的IO打满了。为什么?因为information_schema的查询会锁表啊!

避坑指南:

  • 不要在生产高峰期执行全量采集
  • 建议使用只读账号,权限控制在SELECT级别
  • 设置查询超时,我一般设30秒,超了就跳过
  • 分批次采集,一次别超过50张表

代码示例(Java JDBC采集MySQL元数据):

// 获取指定库的所有表
DatabaseMetaData metaData = connection.getMetaData();
ResultSet tables = metaData.getTables(
    catalog, schemaPattern, tableNamePattern, types
);

while (tables.next()) {
    String tableName = tables.getString("TABLE_NAME");
    String tableType = tables.getString("TABLE_TYPE");
    String remarks = tables.getString("REMARKS");
    
    // 获取每张表的字段信息
    ResultSet columns = metaData.getColumns(
        catalog, schema, tableName, "%"
    );
    while (columns.next()) {
        String colName = columns.getString("COLUMN_NAME");
        int dataType = columns.getInt("DATA_TYPE");
        String typeName = columns.getString("TYPE_NAME");
        int colSize = columns.getInt("COLUMN_SIZE");
    }
}

3.2 日志解析采集:不侵入,但费脑子

有些场景下你不能直连数据库,比如安全限制严格的金融系统。这时候日志解析就派上用场了。

我习惯把日志采集分成两类:

  • 数据库日志:比如MySQL的binlog、Oracle的redo log
  • 应用日志:比如数据平台的ETL日志、调度日志

binlog解析示例(基于Canal):

// 监听MySQL binlog事件
CanalConnector connector = CanalConnectors.newSingleConnector(
    "127.0.0.1", 11111, "example", "", ""
);

connector.connect();
connector.subscribe(".*\\..*");

while (true) {
    Message message = connector.getWithoutAck(100);
    long batchId = message.getId();
    
    for (CanalEntry.Entry entry : message.getEntries()) {
        if (entry.getEntryType() == CanalEntry.EntryType.ROWDATA) {
            CanalEntry.RowChange rowChange = CanalEntry.RowChange.parseFrom(
                entry.getStoreValue()
            );
            // 解析出表名、操作类型、变更前后的数据
            String tableName = entry.getHeader().getTableName();
            CanalEntry.EventType eventType = rowChange.getEventType();
        }
    }
    connector.ack(batchId);
}

个人经验:日志解析最大的好处是对源系统零侵入。我曾经帮一个银行做元数据采集,他们不允许任何第三方工具直连核心库。最后我们通过解析归档的binlog文件,把元数据变化全部抓出来了。虽然开发周期长了点,但安全合规完全没问题。

3.3 API采集:标准化,但依赖接口

现在很多数据平台都提供了元数据API,比如Atlas的REST API、DataHub的GraphQL接口。这种方式适合采集平台自身的元数据。

常见API类型:

平台 接口类型 采集内容
Apache Atlas RESTful 实体类型、分类、血缘关系
DataHub GraphQL 数据集、数据流、Schema
Kafka Schema Registry RESTful Avro/Protobuf Schema
Hive Metastore Thrift 表、分区、存储格式

调用Atlas API获取实体类型的示例:

GET /api/atlas/v2/types/typedefs

Response:
{
  "classificationDefs": [...],
  "entityDefs": [
    {
      "name": "hive_table",
      "superTypes": ["DataSet"],
      "attributeDefs": [
        {"name": "name", "typeName": "string"},
        {"name": "owner", "typeName": "string"},
        {"name": "createTime", "typeName": "date"}
      ]
    }
  ]
}

注意:API采集最怕接口变更。我曾经遇到过,DataHub升级后GraphQL的查询结构变了,采集程序直接崩了。建议:

  • 给API调用加版本号
  • 做好接口兼容性测试
  • 设置熔断机制,接口异常时自动降级

3.4 事件监听采集:实时,但复杂

如果你需要秒级感知元数据变化,事件监听是唯一选择。这种方式通过订阅消息队列或事件总线,实时捕获变更事件。

典型架构:

  • 源系统产生事件 → 发送到Kafka/RabbitMQ → 消费者解析 → 写入元数据存储
  • 支持的事件类型:建表、删表、修改字段、变更分区、更新权限

Kafka事件消费示例:

// 消费元数据变更事件
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "metadata-collector");
props.put("key.deserializer", 
    "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", 
    "org.apache.kafka.common.serialization.StringDeserializer");

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList("metadata-events"));

while (true) {
    ConsumerRecords<String, String> records = consumer.poll(100);
    for (ConsumerRecord<String, String> record : records) {
        String eventJson = record.value();
        // 解析事件,提取表名、操作类型、时间戳
        MetadataEvent event = parseEvent(eventJson);
        updateMetadataStore(event);
    }
}

我的建议:事件监听适合对实时性要求高的场景,比如数据血缘的秒级更新。但别什么都用事件——如果只是每天凌晨跑一次全量采集,用JDBC或API就足够了。事件监听带来的复杂度(消息顺序、重复消费、积压处理)不是小团队能轻易驾驭的。

3.5 四种方式怎么选?

我整理了一张对比表,你根据实际情况对号入座:

维度 JDBC/ODBC 日志解析 API采集 事件监听
实时性 低(定时轮询) 中(近实时) 中(取决于接口) 高(秒级)
侵入性 高(直连数据库) 低(读日志) 中(调用接口) 低(订阅消息)
实现难度 低 高 中 高
适用场景 关系型数据库 安全限制严格的系统 数据平台/工具 实时血缘/变更捕获
维护成本 低 高(日志格式变化) 中(接口版本管理) 高(消息队列运维)

说白了,没有银弹。我一般建议:

  • 核心关系库用JDBC做全量采集,配合binlog做增量
  • 数据平台用API采集,省心
  • 实时场景上事件监听,但要做好兜底
元数据采集技术选型决策流程 元数据采集需求 需要实时采集? 是 事件监听采集 否 允许直连数据库? 是 JDBC/ODBC采集 否 数据平台/工具? 是 API采集 否 日志解析采集 💡 决策要点: 实时性要求高 → 事件监听;允许直连 → JDBC;数据平台 → API;安全限制严 → 日志解析

最后说一句:实际项目中往往是多种方式混用的。比如我最近做的项目,Hive元数据用API采集,MySQL用JDBC+binlog双通道,Kafka Schema用事件监听。别拘泥于单一技术,适合你的就是最好的。