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采集,省心
- 实时场景上事件监听,但要做好兜底
最后说一句:实际项目中往往是多种方式混用的。比如我最近做的项目,Hive元数据用API采集,MySQL用JDBC+binlog双通道,Kafka Schema用事件监听。别拘泥于单一技术,适合你的就是最好的。