背景介绍
元数据是数据平台的衍生数据,如调度任务信息、离线蜂巢表、实时话题、字段信息、存储信息、质量信息、热度信息等。在数据平台建设初期,这类数据主要分散在各个平台子系统的数据库中,如HiveMetaStore、调度系统db等。在此期间,数据平台主要关注服务业务数据需求,平台还关注管理表、ETL编写、配置调度等功能需求。对这些分散的元数据的收集和统一管理没有强烈的需求。
随着数据平台业务规模的增长,平台会沉淀大量的数据表、调度任务等元数据。由于前期业务发展较快,产生了大量的数据管理成本和存储计算成本。此时,模型规范治理、模型变更影响、指标变更定位、重复建设治理等需求场景。会逐渐显现出来。基于这些场景的需求,此时数据平台只提供数据开发相关的功能,难以满足业务需求。需要构建一系列偏向于事后信息查询和治理的产品工具,如数据地图(找号)、血图(定位数据链接)、影响分析工具、资产看板工具、治理工具等。
由于之前的元数据比较分散,系统之间的数据相互耦合,边界不清。无法从全局的角度观察和分析平台数据资产,无法将数据之间的生产加工关系串联起来。因此,构建完善可靠的元数据服务成为满足数据发现和数据治理需求的关键。
元数据基础设施
背景目标
在哔哩哔哩数据平台元数据建设之初,由于缺乏对元数据业务的深入理解和有限的人力投入,实施方案采用了针对特定需求的深度定制。比如你需要某类hive表的字段信息,那么针对这个场景,设计一批Hive表和字段的元数据表,直接连接HMS拉取全量数据,定制HMS的Binlog供业务逻辑消费更改同步,然后通过公开一批查询表字段的HTTP接口提供给需求方查询。
基于这种模型,虽然可以在短时间内满足需求,但暴露出两大问题:1 .灵活性差,实现非常定制,难以支持频繁的边界场景。只需要为新需求安排开发,严重拖慢了业务迭代速度。2.开发维护成本高,大量定制的集合逻辑、异构元数据表、支持各种业务场景的接口在有限的人力资源下难以支撑,始终面临元数据模型变更的问题。
在这种状态下,有一些必然的结果。由于不能快速支撑业务需求,需求方通常会自建线下元数据来运行业务,造成重复建设和后期管理的问题。由于开发和维护成本高,支持元数据业务的同学疲于应付各种诉求,压力很大,还要兼顾各种在线元数据质量问题的调查和运营。
因此,系统化元数据建设的目标之一就是统一元数据。即使用统一的元数据模型、统一的采集方法、统一的存储方法和统一的查询方法来支持上层元数据业务需求。
系统概况
统一元数据模型
元数据模型需要满足三个要求:
确定统一的元数据资源。
描述所有类型的元数据资源。
描述上述元数据资源之间的各种类型的关系。
在这一部分,我们借鉴了业界一些常见的方案,构建了统一的元数据模型来标识URN实体关系。
统一识别协议URN
URN=协议域业务域资源类型的唯一资源ID
每个域由“:”分隔。
其中协议域被全局固定为urn;数据平台内的资源业务域统一为数据中心;资产类型是经过协商和同意的,因此文档在一个统一的w
这里,我们将讨论最重要的资产表的URN定义。我们认知中的表可以来自平台内部,比如最常见的Hive和ClickHouse表,也可以来自平台外部,比如business的Mysql和TiDB,有些是映射到类似KV结构的逻辑表。
在血缘关系场景中,我们需要打通这些跨域数据表之间的关系,所以需要从全局的角度来识别。我们采用的方案是用tab作为这些数据表的统一类型,然后用源、库、表三段公式作为唯一的资源ID来表示各种数据源,和源、库、表、字段四段公式一样扩展到字段。
需要注意的是,如果要使用这个表达式,必须满足一个前提:有统一的数据源管理,并且保证同一个源的数据源名称唯一不变,比如使用同一个mysql集群。
下的数据库中的表,必须在全部业务流程中,收敛为使用同一个数据源。这里会涉及到了关于数据源命名规范的问题,不多做展开。
实体关系模型
上图的模型中大部分还是比较好理解的,但有以下两个概念特别讲解一下。
实体的Aspcet
在通常的理解中,一个实体的全部信息应该来源于一个系统,这样当进行一类资源的采集时,我们只需要找那个系统去同步,但实际会存在一些特殊情况。比如,一张Hive表,它的基础属性都存于HMS之中,但是围绕着Hive表,会建设很多衍生服务,这些服务会单独管理一些衍生的业务属性,例如Hive表的生命周期、安全等级等。
针对同一个实体,它的属性来源分散的情况,我们借鉴了Linkedin开源元数据平台DataHub中的设计,引入Aspcet(切面)概念,对来源不同的属性进行区分。Aspcet在模型中的作用,更重要的是用在元数据采集时,这部分会在后面采集内容说明。
关系的BuilderURN
在维护关系数据时,我们常会遇到一个问题,关系是由谁来构建的。比如离线的表级血缘中,血缘关系通过调度任务来构建,此时血缘的生命周期也应该跟随相应的任务。针对类似场景,我们在关系模型中加入了builderURN作为抽象,也就是构建关系的实体URN,这样我们将任务的URN置于builderURN属性中,而不是作为输入输出中的一个点。这样做有几点好处:
减少关系数据,降低查询复杂度:如果将任务作为关系的一个点,构建表级血缘,要么做实时的跨层查询,要么需要冗余维护额外的数据。
方便生命周期管理:当任务被下线时,我们可以快速查询到由该任务构建的关系,级联进行删除操作。
统一元数据-采集
元数据的采集部分主要涉及几点问题,其中包含技术问题,也包含职责分工边界的问题。
采集方式选型
对采集方式的选择,一般会比较几种方案:
1. 批拉取
采集侧进行调度触发拉取,业务侧支持按业务偏移量进行增量查询。优点:采集配置可控,易监控和运维。缺点:业务侧需要配合进行定制取数逻辑开发,对业务数据的存储更新方式有一定要求。
2. 批上报
业务侧自行调度,按业务偏移量增量查询后自主上报,采集侧被动做消费。优点:整体采集逻辑简单,开发成本低。缺点:无法控制采集配置(频率、间隔),采集问题难监控、难定位,难运维。
3. 埋点上报
业务侧将上报埋点到数据变更流程中。优点:实时性强,对业务数据的存储更新方式无特定要求。缺点:采集问题难监控、难定位,几乎无法运维。
这里我们选型是1和3,权重倾向于可控采集和采集质量保障,对于需要强保障质量的类型,我们主推采用1的方式做采集。对于一些非核心数据,或者存储更新不规范,无法批量取数的场景,也可以选用3的方式由业务自行上报。
业务逻辑谁来维护
为了解藕业务,降低元数据去理解业务含义,维护业务变更等等成本,我们约定统一由数据源头业务负责维护数据模型到统一元数据模型的转换逻辑,也就是说,无论是自助上报,还是接口拉取,我们都会以统一的元数据模型来进行数据交换,避免产生业务逻辑处理各类异构数据。
采集质量保障
采集质量保障是非常重要的一环,直接关系到后续元数据上层业务能否有效开展。在采集质量方面,我们踩过很多坑,比如业务侧硬删数据、业务侧数据事务落库问题、业务侧上报bug、消息中间件不稳定等导致最终数据不一致,且缺少有效的数据监控,定位处理成本非常的高。
基于这些问题,我们建设落地了成元数据质量保障机制,核心思路是以单批次检查和全局兜底检查作为质量问题的发现定位手段,以业务实现规范取数接口支持了采集全量拉取、采集增量拉取、运维补数拉取和运维靶向拉取,作为问题处理手段。最终做到自动化的完成采集质量问题发现、定位、处理整套运维动作。
统一元数据-存储
TIDB – 元数据DB,承载采集到的实体关系数据,作为元数据业务的中心存储。
ES – 查询搜索DB,数据从TIDB的实体表同步,提供元数据检索能力,提供跨源跨表join,分词查询,权重控制,自定义词包等能力。
HugeGraph – 关系搜索DB,数据从TIDB的关系表同步,提供图结构下的深度遍历,路径选择,成环处理等能力。
统一元数据-查询
在元数据查询的场景中,有非常多的定制需求,不仅要满足上层应用对元数据的查询,也要满足来自用户和数据治理层面的突发需求。所以在元数据查询能力建设上,既需要具备通用性,支持各种灵活的查询情况场景,又需要具备可复用性,避免重复建设导致维护成本的上升。
因此我们采用了通用元数据查询的设计思路,查询底层依赖上面Tidb、ES、图数据库的搜索能力。通用查询主要设计了两个核心接口,通用实体查询和通用关系查询,并逐步将上层应用查询使用进行收敛。
通用查询接口的设计中,我们实现了两个重要的功能降低使用成本,提高灵活度 1. 类SQL查询 2. 关联查询
为了使用上的便捷性,我们定制了一个SQLParser的实现,适配SQL的WHERE条件逻辑中 AND、OR、LIKE、IN、=、!= 等算子和组合拼接,最后在内部将其转换为各个引擎定制的DSL发起查询请求。
{ "page": 1, "size": 20, "where": "entity_type = 1 and sec_type = 3 and properties.tabName like '%r_ai.ods.recindexing.archive.test%'"}
由于实际场景中有大量的关联查询需求,而我们的数据存储模型是类似于雪花模型的结构,为了降低多次查询的复杂性,我们用特殊的字段设计和查询语法支持了一次查询时的额外多层关联查询。
{ "page": 1, "size": 500, "where": "entity_type = 7", "extraProperties": { "t1": "*:$.pgUrn.text_pageName", "t2": "7:$.pgUrn.text_userName", "t3": "7:$.pgUrn", "t4": "*:$.pgUrn.bizCtime", "t5": "*:$.dsUrn.sql", "t6": "guanyuanCard:$.dsUrn.datasetStatus" }}
目前,通用元数据查询已经全面应用在数据地图、影响分析、指标取数服务等业务应用场景上面,存量的定制查询也在逐步迁移。
血缘建设
数据血缘是元数据基建中非常比较重点的方向,甚至可以说,元数据建设的收益中,30%~50%是血缘建设。描述好数据的来龙去脉,能充分解释一份数据从哪里来到哪里去,是后续开展数据运维、数据治理工作的关键。
我们将血缘建设主要分成三个主攻方向:提升覆盖、细化粒度、保障准确性。其中第三点保障准确性目前相对较难,我们也还处于探索阶段,所以重点围绕前两个方向来讲。
1. 提升覆盖
提升元数据的覆盖需要两个前提,一是数据生产或使用的链路收敛、系统数据可采集;二是参与数据生产使用的系统,需要有统一的数据定义。
链路收敛意味着分母数量确定,提升覆盖不会变成一个无法预期、无限投入的工作。比如在B站内部,参与数据生产的系统,统一到了平台调度平台、流计算平台、数据集成平台、埋点平台几个有限系统中,我们根据这些系统中的要素去定制血缘解析和采集策略,将数据进行打通,即可覆盖离线、实时、出入仓等关键步骤的血缘,但往往还会存在一些由业务定制的野生调度系统,野生运行脚本等跑数情况,这些场景一般伴随着缺少归属人,生产模式杂乱,缺失生命周期等问题,正常不应该纳入到血缘链路中,最好尽快的收口治理掉。
统一的数据定义,可以参考上面统一资源表达式URN,需要推动各个系统达成共识。尤其对于涉及出入仓的系统,对数据源的统一管理,全面接入是对出入仓数据统一定义的关键点。
目前我们在血缘的覆盖度建设上面比较完善,目前已经较为完整的覆盖了离线链路、实时链路、出入仓表、数据报表等等。
2. 细化粒度
血缘的粒度由大至小分别是 表级 → 字段级 (分区级) → 行级,血缘粒度越小,进行数据链路上下游定位的精度越高,但采集解析存储的难度越大。
表级血缘是非常基础的能力,一般使用类似Antlr等开源的SQL解析器进行ETLSQL静态解析,结果也比较精准。一般的离线调度、实时计算平台都会自建这类scan能力,难点是对于非SQL的ETL任务,比如MRJar、SparkJar类型的任务,解析原生代码的难度很大而且结果很大概率会不准,一般会尽量收敛在重要的链路使用,或者扩充功能,由用户手动维护这类任务的输入输出表。对于出入仓的表血缘,一般则是功能化选择入仓表、出仓表,可以直接获得血缘。
字段级血缘随着平台建设的深入和治理工作的开展,越来越趋于重要,因为从表粒度定位上下游的精度太粗,比如在字段变更影响分析时,通过表血缘会筛出很多实际无依赖表,需要再耗费很多人力去看代码筛选。实现字段级血缘,有三种可选方案:a. 事前+静态 b. 事前+动态 c. 事后+动态。
事前+静态同解析表级血缘的思路一样,但是解析的准确性很差,处理不了类似于select *等不明确写明字段的情况。事前+动态是在任务注册时,通过调用Hive引擎的动态解析能力,产出LineageLog日志,用于字段级血缘解析,这种方法是可行的,优点是获取血缘的时效性比较高,缺点是需要感知生产任务的注册变更主动发起解析,如果生产系统不够收敛,实现的成本较大。事后+动态是在任务实际执行时,经过Hive引擎的动态解析过程后,自动抛出LineageLog,进行字段级血缘解析,这种方案也是可行的,优缺点和事前+动态相反,时效性较低,但是只需要被动采集日志,不用感知任务变化。我们采用的是方案3,当然,在实际情况中,我们还需要面临Hive之外的引擎适配,比如Spark、Presto执行,但思路相类似,都需要引擎侧的支持。
行级血缘只在非常特殊的场景存在需求,比如埋点链路追踪,可以通过其他定制化手段加以解决,统一的行级血缘暂时无法实现。
目前我们的血缘粒度支持到字段级,但是字段级还存在不少的限制,比如某些系统生产的数据不支持字段级,报表血缘不支持字段级等等,此外,一直缺乏对字段级血缘的准确性评估的有效手段,目前只能借助于类似于影响分析、字段属性继承等业务场景的用户反馈。
现状总结&当前规模
目前元数据基建已经建设成熟,拥有基于统一模型的元数据采集、存储、查询、监控、运维的一站式能力。目前建立10+元数据采集上报方,接入实体类型16种,关系类型10种,其中Hive正式表数量6W+,各类任务数量11W+。
表级血缘覆盖从数据入仓到出仓全链路,打通离线表与实时表血缘,表级血缘覆盖平台正规调度任务产出的所有表字段。
元数据通用查询每日支撑各类业务查询PV2.5W次,支撑上层 数据地图、影响分析、血缘地图、取数服务、基线分析 等重要平台应用。
元数据应用-数据地图
找数
找数是数据运营中的关键环节,也是数据地图要解决的核心问题。我们将地图模块分为 基础搜索、分类查询、热度推荐 三部分。
基础搜索重点解决用户主动找数的场景,其中涉及数据模型的搜索召回策略、排序策略。我们将表名、描述信息、责任人、字段、标签等字段作为模型召回字段,通过关键词匹配度、 模型热度、模型质量、模型推荐标 以及适当的权重分配,进行排序控制,最终展现用户需要的搜索结果。
分类查询、热度推荐 重点解决用户被动找数的场景,首先需要对业务域、数据域和数据过程进行合理划分,构建完善可读的数据目录,用户通过对目录信息的浏览,可以定位到具体业务表。热度推荐则是通过模型使用热度,按照部门划分进行排序,推荐出同部门用户高频使用、近期新增的表。
除了Hive表之外,数据地图还提供了 实时Topic、clickhouse表、Bi报表的搜索查询,目前地图搜索日查询PV 4000+。
理解数
为了用户找数后,理解模型数据的内容,极大丰富了表详情页的功能,重点围绕构建表的模型画像、数据画像,这里面非常依赖元数据的基建能力进行采集和质量校验。
模型画像,我们从以下几个方面对表的信息进行了刻画:
基础元数据(表名、字段、分区、路径、格式等)
业务元数据(归属信息、安全等级、业务线、模型信息、生命周期等)
生产元数据(产出任务、基线)4. 质量元数据(DQC任务)
衍生元数据(使用说明、自定义标签、评分)
血缘元信息(表血缘)
变更元信息(变更记录)
成本元信息(表存储占用,分区存储占用,冷存周期,压缩格式)
使用元信息(使用热度)
数据画像,目前支持的功能主要是样例数据和数据探查,用以展示表数据的内容,并具备一些基础统计分析能力。
元数据应用-血缘地图
血缘地图需要满足用户探索数据血缘的需求,是血缘元数据最直接的产品化呈现,在产品设计实现的过程中,我们遇到了非常多的问题,也走了一些弯路,才探索出一套可用的形态。目前最终呈现的数据地图,支持动态配置不同类型数据的展示信息,支持点的动态条件过滤、高亮。
目前血缘地图中涉及的主要实体类型12种,关系构建实体类型4种,日均使用PV 500+。
元数据应用-影响分析
影响分析主要使用场景有两个:
上游数据变更或异常,判断定位下游影响
下游数据异常,进行问题溯源
所以在这个产品定位下,影响分析的核心能力就是支持血缘深层遍历,数据汇总统计,我们在此功能上首次支持了字段血缘。在这个场景中,我们依然要面对数据类型多的问题,初此之外,还要面对深层遍历时长耗时的交互处理,超大数据量(过百层,百万级实体)结果处理,已经超大数据对服务资源占用的影响。针对这几种情况,我们的处理方式是:
异步执行,同步交互(95%可以10s内返回)
利用HugeGraph的图深层遍历能力,隔离服务集群
数据汇总处理业务,隔离到单独服务
相同查询条件结果天级缓存
未来规划
元数据质量保障,目前已经落地一套保障机制,但目前接入保障的场景还比较少,需要长期推广和推动存量上报迁移,形成质量评估的体系。
元数据字典,随着越来越多元数据类型的接入,沉淀了各类元数据的业务属性,要形成基于通用查询的完全自助查询,需要通过建立元数据字典,解决元数据模型和字段业务含义的理解问题。
数据运营体系,随着功能的拓展,平台功能已经覆盖到用户方方面面的需求。但平台建设,除了建工具之外,还有需要建流程,建机制。目前在找数用数场景中,最核心的痛点就是模型质量不高,模型分类不准不全,下游使用存在数据口径问题,数据质量问题、数据使用问题。我们需要建立数据运营机制,从数据供给侧建立成本指标和产出指标,数据消费侧打通数据使用链路血缘,建立收益指标,利用地图的能力保障数据生产消费两端的信息畅通。
数据治理,在数据平台的建设中,由于各种历史原因,普遍存在大量重复建设,不规范的行为动作,导致数据成本,人力成本的多余消耗。随着降本增效成为业务重心,我们需要从工具层面开展数据治理建设,利用已经完善的元数据基建能力,规模化治理流程,扩大治理范围,提升治理效率。