5.2 元数据
5.2.1 工具
数仓开源元数据项目对比(Apache Atlas、Apache Gravitino、DataHub、OpenMetadata、Amundsen、Metacat、Marquez)
5.2.1.1 起源与发展历程
|------------------|------------------------------------------------------------------|------------------------------------------------------|
| 项目 | 起源与关键节点 | 发展特点 |
| Apache Atlas | 2015 年由 Hortonworks 发起,2017 年成为 Apache 顶级项目,最初为 Hadoop 生态数据治理而生。 | 老牌项目,历经 10 年迭代,功能成熟,早期绑定 Hadoop 生态,近年逐步适配云原生。 |
| Apache Gravitino | 2023 年由网易、星环等企业联合贡献至 Apache 孵化器,2025年5月毕业,定位 "统一元数据服务"。 | 新兴项目,理念超前(聚焦元数据统一接入),目前处于功能快速完善阶段。 |
| DataHub | 2019 年 LinkedIn 开源,2022 年捐给 LF AI & Data 基金会,解决内部 "数据发现难" 问题。 | 互联网企业驱动,强调实时性与用户体验,LinkedIn 持续投入,版本迭代快(每 1-2 月一个版本)。 |
| OpenMetadata | 2021 年由 Collibra 前核心团队创立,2022 年加入 Linux 基金会,主打 "一体化数据治理"。 | 治理基因浓厚,集成元数据、质量、协作功能,开箱即用,适合中小团队快速落地。 |
| Amundsen | 2019 年 Lyft 开源,名字源自 "挪威探险家",聚焦 "数据发现"(类似数据领域的 Google)。 | 轻量实用,核心解决分析师 "找数据" 问题,Lyft、Airbnb 等企业内部验证,功能聚焦不冗余。 |
| Metacat | 2015 年 Netflix 开源,最初为解决多数据源(Hive、Redshift、S3)元数据统一访问问题。 | 定位 "元数据中间层",功能极简,无治理 / 血缘,仅做聚合与转发,维护成本低。 |
| Marquez | 2018 年 WeWork 开源,后被 The Linux Foundation 接管,专注 "数据管道血缘" 跟踪。 | 聚焦数据工程场景,深度绑定 Airflow,轻量专一,不扩展其他元数据类型(如 BI、ML)。 |
点击图片可查看完整电子表格
5.2.1.2 关键能力对比
|------------------|----------------------|-----------------------------|--------------------------|---------------------------|--------------|-----------------|
| 能力维度 | 元数据类型 | 血缘管理 | 数据治理 | 搜索与发现 | 协作功能 | 实时性 |
| Apache Atlas | 表、字段、分区、分类、权限实体 | 表级 / 字段级,支持 Hive/Spark 静态血缘 | 标签体系、数据分级、细粒度权限、合规审计 | 基础全文检索(Solr) | 无 | 批处理更新(T+1) |
| Apache Gravitino | 表、列、视图、函数、存储位置 | 表级,跨引擎(Spark/Flink)聚合 | 基础标签、数据资产目录 | 基础搜索(基于存储索引) | 无 | 近实时(依赖数据源推送) |
| DataHub | 表、字段、BI 报表、ML 模型、仪表盘 | 表级 / 字段级,实时捕获(Kafka 驱动) | 标签、术语表、所有权管理 | 模糊匹配、过滤、排序(Elasticsearch) | 评论、通知、变更日志 | 实时(事件驱动,毫秒级) |
| OpenMetadata | 表、字段、管道、BI、ML 模型、SLA | 表级 / 字段级,自动解析 SQL/Spark | 数据质量(Profiler)、SLA 管理、权限 | 精准搜索、关联推荐(Elasticsearch) | 评论、任务分配、团队协作 | 准实时(定时同步 + 触发式) |
| Amundsen | 表、字段、查询历史、用户行为 | 表级,基于 SQL 解析 | 无 | 热门表推荐、按使用量排序 | 表描述、使用文档 | 准实时(定时同步) |
| Metacat | 表、分区、存储路径 | 无 | 无 | 无(仅转发查询) | 无 | 实时(被动转发) |
| Marquez | 数据集、作业、运行实例 | 作业 - 数据集依赖(表级) | 无 | 基础查询 | 无 | 准实时(作业运行时同步) |
点击图片可查看完整电子表格
5.2.1.3 数据源支持
|------------------|---------------------------------------------------|------------------------------------------------------|----------------------------------|
| 项目 | 核心支持数据源(数据库 / 数仓) | 扩展支持(BI / 管道 / ML) | 适配特点 |
| Apache Atlas | Hive、HBase、Spark、Kafka、SQL Server | Tableau(有限)、NiFi | 强适配 Hadoop 生态,对云数仓(Snowflake)支持弱 |
| Apache Gravitino | Hive、Glue、Snowflake、BigQuery、PostgreSQL、Spark | Flink、Trino | 兼顾传统与云原生,通过 "连接器" 扩展,覆盖广 |
| DataHub | Hive、BigQuery、Redshift、Snowflake、MySQL、PostgreSQL | Tableau、Power BI、Airflow、TensorFlow | 互联网场景全覆盖,云数仓 / BI 适配完善 |
| OpenMetadata | Hive、BigQuery、Redshift、Snowflake、MySQL、Oracle | Tableau、Power BI、Airflow、Fivetran、Great Expectations | 连接器丰富(30+),开箱即用,无需二次开发 |
| Amundsen | Hive、Presto、Redshift、BigQuery | Airflow、Jupyter | 聚焦分析师常用数据源,适配轻量简洁 |
| Metacat | Hive、Redshift、S3、Athena、MySQL | 无(仅元数据聚合) | 多数据源统一接口,屏蔽底层差异 |
| Marquez | Hive、PostgreSQL、BigQuery | Airflow、Spark、Flink | 仅支持数据管道相关数据源,适配极专一 |
点击图片可查看完整电子表格
5.2.1.4 技术栈对比
|------------------|-------------------|-------------------|---------------|-------------|------------------|------------------|
| 项目 | 后端语言 | 存储数据库 | 搜索组件 | 消息队列 | 前端技术 | 部署复杂度 |
| Apache Atlas | Java | HBase(主存储) | Solr | Kafka(可选) | AngularJS | 高(依赖 HBase/Solr) |
| Apache Gravitino | Java | MySQL/PostgreSQL | 无(依赖存储索引) | 无 | 无(仅 API) | 低(轻量服务) |
| DataHub | Java/Scala | PostgreSQL | Elasticsearch | Kafka(核心) | React | 中(需部署 Kafka/ES) |
| OpenMetadata | Java(Spring Boot) | PostgreSQL | Elasticsearch | 无(定时同步) | React | 低(单服务 + 双存储) |
| Amundsen | Python(Flask) | Neo4j(血缘)+ ES(搜索) | Elasticsearch | 无 | React | 中(多组件联动) |
| Metacat | Java | MySQL/PostgreSQL | 无 | Kafka(事件通知) | 无(仅 API) | 低(单服务) |
| Marquez | Java(Dropwizard) | PostgreSQL | 无 | 无 | 无(仅 API + 简单 UI) | 低(单服务) |
点击图片可查看完整电子表格
5.2.1.5 社区活跃度(截至 2025 年 10 月)
|------------------|--------------|-------|--------------|------------|-----------------------|
| 项目 | GitHub Stars | 贡献者数量 | 近 6 月版本更新 | Issue 响应速度 | 企业用户案例 |
| Apache Atlas | 4.8k | 150+ | 1 个(minor) | 较慢(7-14 天) | 华为、腾讯、金融机构 |
| Apache Gravitino | 1.2k | 50+ | 3 个(功能迭代) | 较快(3-7 天) | 网易、星环科技(初期) |
| DataHub | 11.5k | 400+ | 6 个(含 major) | 快(1-3 天) | LinkedIn、Uber、Spotify |
| OpenMetadata | 8.2k | 200+ | 4 个(功能迭代) | 快(1-3 天) | Netflix、Walmart、Adobe |
| Amundsen | 4.2k | 100+ | 2 个(minor) | 中(3-7 天) | Lyft、Airbnb、Square |
| Metacat | 1.8k | 50+ | 1 个(维护性) | 慢(14 + 天) | Netflix、Uber |
| Marquez | 2.1k | 80+ | 2 个(minor) | 中(5-10 天) | WeWork、Zalando |
点击图片可查看完整电子表格
5.2.1.6 总结与选型建议
核心差异总结
- 治理导向:Apache Atlas(企业级合规,重权限 / 分级)、OpenMetadata(一体化轻治理,含质量 / 协作);
- 实时与发现:DataHub(实时元数据更新,搜索体验佳)、Amundsen(分析师友好,数据发现效率高);
- 轻量与专一:Metacat(元数据统一访问层)、Marquez(数据管道血缘跟踪);
- 未来潜力:Apache Gravitino(统一元数据标准,适配混合数据栈)。
场景化选型建议
- 大型企业级数据治理(金融 / 政务) :选Apache Atlas。成熟稳定,支持细粒度权限与合规审计,适配复杂组织架构,但需接受部署复杂度与 Hadoop 生态依赖。
- 互联网 / 电商(实时元数据 + 多场景) :选DataHub。事件驱动架构支持实时更新,覆盖表、BI、ML 全资产,社区活跃,适合快速迭代的业务团队。
- 中小团队 / 初创公司(快速落地治理) :选OpenMetadata。一体化功能(元数据 + 质量 + 协作)开箱即用,部署简单,文档完善,无需专业数据治理团队。
- 分析师主导(数据发现优先) :选Amundsen。搜索体验类似 Google,支持热门表推荐与查询历史关联,轻量化不冗余,适合分析师自主找数据。
- 多数据源聚合(多云 / 混合架构) :选Metacat。作为元数据中间层屏蔽底层差异,无侵入性,适合已有多数据栈(Hive+Redshift+S3)的企业。
- 数据工程团队(管道血缘跟踪) :选Marquez。深度集成 Airflow,专注作业 - 数据集依赖,轻量专一,适合 ETL 工程师跟踪数据流向。
- 混合数据栈(Hadoop + 云数仓) :尝试Apache Gravitino。理念先进,支持统一元数据接入,适合长期规划,但需容忍部分功能待完善。
5.2.2 实施方法
任务与数据存储访问记录关联的解决方案
要建立 Hive、Spark、Flink 等线上任务与 OSS、StarRocks 的审计日志访问记录之间的关联,核心在于实现任务唯一标识在整个数据访问链路中的传递与记录。以下是具体实现方案:
一、任务唯一标识设计
设计全局唯一的任务标识符(Task ID),格式建议:
|-------------------------------------------|
| Plain Text [业务线]-[任务类型]-[环境]-[序号] |
示例:
- recmd-hive-prod-001(推荐业务线 Hive 生产任务)
- user-spark-prod-002(用户业务线 Spark 生产任务)
- log-flink-prod-003(日志业务线 Flink 生产任务)
Task ID 需满足:
- 全局唯一性
- 包含业务属性,便于分类统计
- 与任务调度系统(如 Airflow、DolphinScheduler)中的任务 ID 保持一致
二、任务标识在计算引擎中的传递
2.1 Hive 任务
通过hiveconf传递任务标识,并配置 Hive 在访问数据时携带该标识:
bash
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Bash # 提交Hive SQL任务时指定Task ID beeline -u "jdbc:hive2://prod-hive:10000/prod_db;principal=hive/prod-hive@BIGDATA.COM" \--hiveconf task.id=recmd-hive-prod-001 \--hiveconf ranger.audit.taskid=recmd-hive-prod-001 \-f /scripts/daily_recmd.sql |
在 Hive 配置中关联任务标识:
xml
|------------------------------------------------------------------------------------------------------------------------------------------------------------|
| XML <!-- hive-site.xml 配置 --> <property> <name>hive.semantic.analyzer.hook</name><value>com.bigdata.hook.TaskIdAuditHook</value> </property> |
自定义 Hook 实现(传递 Task ID 到 Ranger 审计):
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Java public class TaskIdAuditHook implements SemanticAnalyzerHook { @Override public ASTNode preAnalyze(ASTNode ast, Context context) { // 从hiveconf获取任务ID String taskId = HiveConf.getVar(context.getConf(), HiveConf.ConfVars.HIVESESSIONSPECIFICPARAMS).get("task.id", "unknown"); // 设置Ranger审计上下文 if (taskId != null && !taskId.isEmpty()) { RangerPerfTracer.logParam("taskId", taskId); // 将Task ID存入ThreadLocal,供Ranger审计插件使用 AuditContext.setTaskId(taskId); } return ast; } } |
2.2 Spark 任务
通过 Spark 配置传递 Task ID,并在访问数据时携带:
bash
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Bash spark-submit \--master yarn \ --deploy-mode cluster \--keytab /etc/keytabs/recmd-prod.keytab \--principal recmd-prod@BIGDATA.COM \--conf spark.app.name=recmd-spark-prod-002 \--conf spark.task.id=recmd-spark-prod-002 \--conf spark.hadoop.ranger.audit.taskid=recmd-spark-prod-002 \--class com.data.RecommendationEngine \ /opt/jobs/recommendation.jar |
Spark 读取 OSS/StarRocks 时传递 Task ID:
scala
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Scala // 读取OSS数据时携带Task ID val df = spark.read .option("taskId", spark.conf.get("spark.task.id")).parquet("oss://prod-bucket/recommendation/data/") // 写入StarRocks时携带Task ID df.write .format("starrocks").option("jdbc.url", "jdbc:mysql://starrocks-fe:9030").option("load-url", "starrocks-fe:8030").option("table.identifier", "prod_db.user_recmd").option("taskId", spark.conf.get("spark.task.id")).save() |
2.3 Flink 任务
通过 Flink 配置传递 Task ID,并在访问外部系统时携带:
bash
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Bash ./bin/flink run-application \ -t yarn-application \ -Dsecurity.kerberos.login.principal=recmd-prod@BIGDATA.COM \ -Dsecurity.kerberos.login.keytab=/etc/keytabs/recmd-prod.keytab \ -Dtask.id=recmd-flink-prod-003 \ -Dflink.ranger.audit.taskid=recmd-flink-prod-003 \ -c com.data.LogProcessor \ /opt/jobs/log_processor.jar |
Flink 消费 Kafka 并写入 OSS 时传递 Task ID:
java
运行
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Java // 配置OSS访问时的Task ID Configuration conf = new Configuration(); conf.setString("fs.oss.task.id", getRuntimeContext().getExecutionConfig().getGlobalJobParameters().toMap().get("task.id")); // 使用带Task ID的配置创建FileSystem FileSystem ossFs = FileSystem.get(new URI("oss://prod-bucket/logs/"), conf); // 写入数据时携带Task ID DataStream<String> logStream = ...; logStream.addSink(new RichSinkFunction<String>() { @Override public void invoke(String value, Context context) throws Exception { // 写入逻辑中包含Task ID String taskId = getRuntimeContext().getExecutionConfig().getGlobalJobParameters().toMap().get("task.id"); // ... }}); |
三、数据存储审计日志的任务标识记录
3.1 OSS 访问审计配置
配置 OSS 服务记录访问来源的 Task ID:
- 通过 SDK 传递 Task ID:
java
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Java // OSS客户端配置Task ID OSSClientBuilder builder = new OSSClientBuilder(); ClientConfiguration clientConfig = new ClientConfiguration(); clientConfig.setUserAgent("taskId:recmd-hive-prod-001"); // 包含Task ID OSS ossClient = builder.build(endpoint, accessKeyId, accessKeySecret, clientConfig); |
- 配置 OSS 访问日志格式 :确保 OSS 访问日志包含user-agent字段(其中包含 Task ID)
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Plain Text [timestamp] [remote_ip] [user_agent] [request_id] [operation] [bucket] [object] [request_size] [response_size] [duration] [status_code] |
- 日志解析规则 :从user_agent中提取 Task ID:
regex
|---------------------------------------|
| Plain Text taskId:([a-zA-Z0-9\-]+) |
3.2 StarRocks 访问审计配置
配置 StarRocks 记录查询请求的 Task ID:
- 修改 StarRocks FE 配置:
xml
|-----------------------------------------------------------------------------------------------------------------------------------------------|
| XML <!-- fe.conf 配置 --> audit_log_level = INFO audit_log_file = /var/log/starrocks/fe/audit.log audit_log_include_variables = true # 记录会话变量 |
- 查询时传递 Task ID:在 SQL 语句前设置会话变量传递 Task ID:
sql
|------------------------------------------------------------------------------------------------------------------------------------------|
| SQL -- Hive/Spark/Flink访问StarRocks时执行 SET @task_id = 'recmd-spark-prod-002';SELECT * FROM prod_db.user_profile WHERE dt = '2023-10-01'; |
- StarRocks 审计日志格式 :确保审计日志包含user_vars字段,从中提取task_id
四、Ranger 审计日志的增强配置
修改 Ranger 配置,确保审计日志包含 Task ID:
xml
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| XML <!-- ranger-admin-site.xml 配置 --> <property> <name>ranger.audit.log4j.appender.AUDITFILE.layout.ConversionPattern</name> <value>{"eventTime":"%d{ISO8601}","reqUser":"%X{username}","accessType":"%X{accessType}", "resource":"%X{resource}","result":"%X{result}","taskId":"%X{taskId}", "clientIP":"%X{clientIP}","sessionId":"%X{sessionId}","requestData":"%X{requestData}"}%n</value> </property> |
自定义 Ranger 审计插件,从计算引擎上下文提取 Task ID:
java
运行
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Java public class CustomRangerAuditHandler extends RangerDefaultAuditHandler { @Overridepublic void logAudit(RangerAuditEvent auditEvent) { // 从ThreadLocal获取计算引擎设置的Task ID String taskId = AuditContext.getTaskId(); if (taskId != null && !taskId.isEmpty()) { auditEvent.setAdditionalInfo("taskId", taskId); } super.logAudit(auditEvent); } } |
五、方案总结
通过以上方案,实现了线上任务与数据存储访问记录的关联,关键要点包括:
- 统一的任务标识:设计全局唯一的 Task ID,作为关联的核心键值
- 全链路标识传递:在计算引擎(Hive/Spark/Flink)中传递 Task ID,并在访问数据存储时携带
- 审计日志增强:配置 OSS、StarRocks 和 Ranger 记录 Task ID,确保审计日志包含关联所需信息
该方案可实现任务级别的数据访问审计,为权限优化、成本核算和安全审计提供精准的数据支持。