深入理解 DataHub 的广义元数据架构(GMA):多存储引擎背后的统一后端基础设施
【免费下载链接】datahubThe Context Platform for your Data and AI Stack项目地址: https://gitcode.com/GitHub_Trending/da/datahub
导读
GMA(Generalized Metadata Architecture,广义元数据架构)是 DataHub 的后端基础设施,它摒弃了"单库打天下"的传统设计,通过组合文档存储、图数据库与全文检索引擎,分别服务文档 CRUD、复杂查询、图遍历和全文搜索/自动补全四类最常见的元数据访问模式。本文以 docs/what/gma.md 为核心,结合仓库内的服务架构、元数据事件定义与 metadata-io 源码实现,为你完整拆解 GMA 的设计动机、分布式部署模型、标准化访问层以及从写入到索引的完整数据通路,帮助你理解 DataHub 元数据平台"既能快读、又能深查、还能追关系"的底层原理。
GMA 是什么:DataHub 的元数据后端
GMA 是 DataHub 的后端基础设施(backend infrastructure),承载着整个平台元数据的存储、访问与索引。它区别于传统架构的关键点在于:GMA 不复用单一存储技术,而是利用多种专门的存储技术来高效服务四种最常见的查询模式:
- 面向文档的 CRUD(Document-oriented CRUD):按主键读取/写入一个实体的一条或多条元数据记录;
- 复杂查询(Complex queries):包括跨分布式表的 join 查询,用于在元数据之间进行关联分析;
- 图遍历(Graph traversal):沿实体间的边(如血缘、所有权、成员关系)进行多跳遍历;
- 全文搜索与自动补全(Fulltext search and autocomplete):对元数据做关键字检索与输入提示。
这种"按需选型、多存储协同"的思路,与 docs/architecture/metadata-serving.md 中描述的服务层路由策略完全一致:主键读取路由到文档存储(RDBMS 如 MySQL、Postgres 或 Cassandra),全文与高级搜索路由到搜索索引,复杂图查询(如血缘)路由到图索引。
分布式模型:每个团队拥有自己的 GMS
GMA 还拥抱了一种分布式模型:每个团队各自拥有、开发并运维属于自己的元数据服务,即 GMS(Generalized Metadata Service)。这些分散的元数据会被自动聚合,填充到中央的 元数据图 和 搜索索引 中。这一设计之所以可行,完全依赖于标准化的元数据模型与标准化的访问层。
从 docs/what/gms.md 可以看到 GMS 的定位:元数据通过名为 GMS 的微服务对外提供,GMS 通常暴露 Rest.li API,并必须通过 GMA DAO 访问元数据(DAO 抽象详见 metadata-serving)。GMA 在设计上支持一组分布式的 GMS 集群,每个 GMS 只服务 GMA 图的一个子集;不过为了简化部署,当前仓库实际采用的是单一的集中式 GMS,由它服务所有实体类型。
分布式带来的实际收益
GMA 团队相信,这套架构能给任何"需要存储和访问元数据"的团队带来巨大杠杆(tremendous leverage)。具体体现在:
- 组织边界清晰:不同团队可以独立演进自己的 GMS 服务,互不阻塞;
- 数据自动汇聚:团队本地写入的元数据通过标准化事件流自动汇入全局图与索引;
- 模型先行(model-first):标准化元数据建模推动了一种"先定义模型、再开发功能"的开发方式,最终形成一个更简洁、更一致、高度互联的元数据生态,惠及所有 DataHub 用户。
标准化的元数据模型:GMA 的基石
GMA 之所以能让不同团队的 GMS 数据自动聚合,前提是大家都遵循同一套元数据模型。DataHub 采用 schema-first(模型优先)方式,使用 LinkedIn 开源的 Pegasus schema 语言(PDL)并扩展自定义注解来建模,概念上由四类抽象构成(详见 docs/modeling/metadata-model.md):
- 实体(Entity):元数据图中的主节点,由类型(如
dataset)、唯一标识(URN)和一组元数据属性分组(即方面)构成; - 方面(Aspect):描述实体某一特定侧面的属性集合,是 DataHub 中最小的原子写入单位,同一实体的多个方面可被独立更新(详见 docs/what/aspect.md);
- 关系(Relationship):两个实体之间的命名边,通过在方面内以"外键"字段配合
@Relationship注解声明,支持双向遍历(详见 docs/what/relationship.md); - 标识(Key 与 Urn):Key 是包含实体唯一标识字段的特殊方面,可序列化为字符串形式的 URN 用于主键查找。
模型定义集中在entity-registry.yml(见 metadata-models/src/main/resources/entity-registry.yml),GMS 启动时校验该注册表并确保每个方面名都能找到对应的 PDL schema。这种"以 YAML 配置登记实体/方面"的方式,使元数据模型的演进从"新建 Snapshot/Aspect 文件"简化为"修改配置",这正是 GMA 标准化模型能够长期演化的关键。
GMA 的图:以 Neo4j 承载实体与关系
所有实体与关系都存储在图数据库中——当前仓库实现为Neo4j(图相关实现位于 metadata-io/src/main/java/com/linkedin/metadata/graph,其中neo4j/与elastic/两个子包分别对应图存储与基于 Elasticsearch 的图查询后端)。图始终代表"世界的当前状态",本身不直接支持版本化或历史记录。
但正如 docs/what/graph.md 所指出的,图本质上只是所有元数据方面的派生视图,因此永远可以从历史的 MAE(Metadata Audit Event)/MCL 事件流直接重建。由此引出一个强大能力:通过把事件流回放到某个时间点,就能构建该时刻图的特定快照。
从理论上讲,GMA 图可以替换为任何支持以下操作的通用 OLTP 图数据库:
- 节点与边的动态创建、修改与删除;
- 为每个节点和边动态附加键值属性;
- 对特定节点或边属性的事务性部分更新;
- 基于 ID 的节点与边快速检索;
- 同时高效支持"图遍历 + 属性值过滤"的查询;
- 支持高效的双向图遍历。
这六项要求界定了 GMA 图存储的最小能力集,也是评估"能否作为 GMA 图后端"的准入标准。
GMA 的搜索索引:以 Elasticsearch 承载全文与自动补全
每一种搜索文档类型(即实体类型)都会映射到 Elasticsearch 中一个独立的搜索索引(search index)。除了搜索引擎的标准能力(analyzer、tokenizer、filter queries、facet、sharding 等)之外,GMA 还额外支持以下特性(详见 docs/what/search-index.md):
- 索引文档的部分更新(partial update of indexed documents);
- 多值字段上的成员测试(membership testing on multi-value fields);
- 索引间的零停机切换(zero downtime switch between indices)。
搜索查询的抽象层由 Search DAO 提供(详见 metadata-serving.md 的 Search DAO 一节),对应源码可查看 metadata-io/src/main/java/com/linkedin/metadata/search 下的SearchService、LineageSearchService与elasticsearch/子包。
搜索自动化(TBD)
GMA 的长期目标(文档中标注为 TBD)是自动化索引创建、schema 演化与重建(reindexing),让团队只需关注搜索文档模型和自定义的 Index Builder 逻辑。具体设想是:当逻辑发生变化时,自动创建新版本的索引并从历史 MAE 回放填充;待填充完毕后,团队只需在 GMS 中做一次简单配置切换即可上线新版本,需要时还能随时回滚到旧版索引。这与图"从事件流重建"的思路一脉相承——事件流是事实来源,所有索引视图皆可派生。
端到端数据通路:从 MCP 提案到图与索引
要理解 GMA 如何把"分布式 GMS 的写入"汇聚为"中央图与索引",需要看清其事件驱动的主链路。DataHub 依赖几类关键 Kafka 事件(详见 docs/what/mxe.md):
- Metadata Change Proposal(MCP):对元数据图提出变更请求,是摄入的中心环节。可通过 Kafka 异步发布,也可直接调用服务层 HTTP 端点获得同步成功/失败响应(见 docs/architecture/metadata-ingestion.md)。默认 topic 为
MetadataChangeProposal_v1。 - Metadata Change Log(MCL,分 Versioned 与 Timeseries 两类):写入持久化存储成功后立即发出的提交事件。默认 topic 分别为
MetadataChangeLog_Versioned_v1与MetadataChangeLog_Timeseries_v1。 - Platform Event(PE):DataHub 自身产生的业务逻辑事件(如 Entity Change Event),默认 topic 为
PlatformEvent_v1。
整条链路的消费端由两个 Spring job 承担(见 metadata-jobs):
- mce-consumer-job:消费 Metadata Change Proposal,通过
/ingest端点写入 DataHub Metadata Service(datahub-gms); - mae-consumer-job:消费 Metadata Change Log,将变更应用到图与搜索索引。该 job 是**实体无关(entity-agnostic)**的,会按需执行对应的图与搜索索引 builder;builder 负责根据元数据变更告诉 job 如何更新图与索引。为确保变更按正确的时序处理,MCL 按实体 URN 分键——同一实体的所有 MCL 会由单个线程顺序处理(详见 docs/architecture/metadata-serving.md 的 Metadata Index Applier 一节)。
MCP 的一个完整示例
下面是一个请求更新 Dataset 的ownership方面的 MCP 示例(来自 docs/what/mxe.md),展示了方面载荷如何以 JSON 字符串形式嵌在aspect.value字段中:
{ "entityType": "dataset", "entityUrn": "urn:li:dataset:(urn:li:dataPlatform:hdfs,SampleHdfsDataset,PROD)", "changeType": "UPSERT", "aspectName": "ownership", "aspect": { "value": "{\"owners\":[{\"type\":\"DATAOWNER\",\"owner\":\"urn:li:corpuser:datahub\"}],\"lastModified\":{\"actor\":\"urn:li:corpuser:datahub\",\"time\":1651516640488}}", "contentType": "application/json" }, "systemMetadata": { "lastObserved": 1651516640493, "runId": "no-run-id-provided", "registryName": "unknownRegistry", "registryVersion": "0.0.0.0-dev", "properties": null } }注意changeType支持CREATE、UPSERT、DELETE(PATCH对特定方面有有限支持),contentType目前仅支持application/json;entityType与实体注册表中的实体名一一对应(如dataset)。MCL 与 MCP 结构几乎一致,只是额外增加了previousAspectValue、previousSystemMetadata与created(审计戳)字段,用于描述变更前后的完整状态——这正是重建索引视图所必需的"事件事实"。
查询路径:GMA 四类模式在服务层的落地
把四种查询模式映射到 docs/architecture/metadata-serving.md 的"元数据查询服务"一节,可以看到清晰的路由分工:
| 查询类型 | 路由目标 | 典型场景 |
|---|---|---|
| 主键读取 | 文档存储(RDBMS) | 按dataset-urn获取数据集 schema 元数据 |
| 次级索引读取 | 搜索索引(或强一致次级索引) | 按属性过滤的元数据查询 |
| 全文/高级搜索 | 搜索索引 | 关键字搜索、自动补全 |
| 复杂图查询 | 图索引 | 血缘(lineage)、所有权、成员关系多跳遍历 |
这也解释了为什么 GMA 需要"多存储协同":没有任何单一数据库能在文档读写、复杂 join、图遍历和全文检索四个维度上同时达到最优,而 GMA 通过标准化模型 + 事件流 + 索引 applier,让每个存储各司其职,同时通过 MCL 事件流(这是一个公开 API,可被 Actions Framework 等外部系统订阅)实时响应元数据变化。
从源码看 GMA 的实现落点
- 图存储抽象:图查询与存储实现集中在 metadata-io/src/main/java/com/linkedin/metadata/graph,
neo4j/子包是文档所描述的 Neo4j 后端,elastic/子包则提供了基于 Elasticsearch 的图查询实现(JavaGraphClient、SiblingGraphService等类封装了图客户端与聚合服务)。 - 搜索服务抽象:metadata-io/src/main/java/com/linkedin/metadata/search 中的
SearchService、LineageSearchService以及elasticsearch/子包,落实了"独立索引 + 部分更新 + 零停机切换"等 GMA 搜索特性。 - 事件消费任务:
mae-consumer-job与mce-consumer-job两个 Spring job(见 metadata-jobs)分别实现了 MCL 的索引应用与 MCP 的写入,是 GMA "分布式写入、集中式汇聚"物理实现的关键一环。 - 模型标准化:metadata-models 模块(含 693 个 PDL 文件)与
entity-registry.yml共同定义了 GMA 之上的统一模型层,所有 GMS、DAO、索引 builder 均建立在这一模型之上。
总结
GMA 的核心设计可以浓缩为三句话:多存储按需选型(文档、图、搜索索引各司其职)、事件流驱动视图派生(图与索引都可从 MCL/MAE 重建,支持时间点快照与索引零停机切换)、模型与访问层标准化(统一的 PDL 模型与 Rest.li/DAO 抽象,让分布式 GMS 的元数据得以自动汇聚)。对任何打算深入 DataHub 二次开发或自建元数据平台的团队而言,理解 GMA 就等于掌握了这套系统的"地基"——它解释了为什么 DataHub 既能高效支撑文档式读写,又能胜任血缘图遍历与全文检索,同时还能在索引损坏时从事件流中一键重建。
延伸阅读:GMS 微服务层 · GMA 图 · GMA 搜索索引 · 元数据事件(MCP/MCL/PE) · 服务层架构 · 元数据模型 · 方面(Aspect) · 关系(Relationship)
【免费下载链接】datahubThe Context Platform for your Data and AI Stack项目地址: https://gitcode.com/GitHub_Trending/da/datahub
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考