查看原文
其他

Atlas——元数据存储模型分析

导语:Atlas 是一个可扩展的核心基础治理服务集 - 使企业能够有效地和高效地满足 Hadoop 中的合规性要求,并允许与整个企业数据生态系统的集成。该项目用于管理共享元数据、数据分级、审计、安全性以及数据保护等各个方面,是数据治理的重要组成部分。本文介绍Atlas的存储子系统,分析Atlas的存储模型和各个元数据要素的存储结构。

Atlas简介

Atlas 是一个可扩展和可扩展的核心基础治理服务集 - 使企业能够有效地和高效地满足 Hadoop 中的合规性要求,并允许与整个企业数据生态系统的集成。从具体功能点看,atlas可以完成元数据系统的以下管理需求:

  • 数据分类:委员数据导入或定制分类和标签,可以自动捕获被分类元数据之间的传播关系。

  • 集中审计:记录应用与数据交互的安全访问信息以及具体的执行步骤等操作痕迹。

  • 搜索与血缘:支持按全文、按分类标签、类sql等各种方式的查询。 对数据集血缘关系的可视化浏览使用户可以下钻到操作,安全以及数据起源相关的信息

  • 安全策略:支持基于角色的运行时合规策略;支持数据信息脱敏如属性级别的masking


其整体架构图如下图所示:


整体来看,atlas由Core、integration、metadata source和Apps几大部分组成。


core包含类型系统、元数据导入导出、图引擎三大模块。类型系统定义了元数据对象的模型,也是下文要继续介绍的重点。导入导出模块支持元数据快速导入到atlas,以及将atlas检测到的元数据更改以事件方式通知到下游服务。图引擎是atlas的存储和计算推导基础,目前采用janusgraph实现。


integration是atlas的IO子系统,支持以REST API和消息系统两种方式将元数据导入Atlas。其中消息系统方式支持kafka作为中间件,可以让atlas和其他数据源服务解耦,具有更好的扩展性。


metadata source模块是atlas的数据源插件,目前支持从常见的大数据服务中捕获元数据以及其变更信息,并及时通知到消息中间件。新的大数据服务要接入atlas,可以在此扩展数据源即可。


Apps是构建在core之上的元数据应用,包括基于web的应用、基于标签的策略和业务分类系统。


Atlas存储

下面从三个方面介绍Atlas存储:类型系统、图存储模型以及类型是实体的存储结构。


类型系统

Atlas 允许用户为他们想要管理的元数据对象定义一个模型。该模型由称为 "类型" 的定义组成。被称为 "实体" 的 "类型" 实例表示被管理的实际元数据对象。类型系统是一个组件,允许用户定义和管理类型和实体。由 Atlas 管理的所有元数据对象(例如Hive表)都使用类型进行建模,并表示为实体。要在Atlas中存储新类型的元数据,需要了解类型系统组件的概念。


Atlas中的 "类型" 定义了如何存储和访问特定类型的元数据对象。类型表示了所定义元数据对象的一个或多个属性集合。具有开发背景的用户可以将 "类型" 理解成面向对象的编程语言的 "类" 定义的或关系数据库的 "表模式"。


Atlas中的类型分为两类:原生类型和结构化类型;原生类型用来描述基础属性的类型,结构化类型用来构造Atlas中元数据相关模型。


原生类型包括:Int,String,Boolean,Date,枚举等等,无需过多解释。


结构化类型包括:集合类型:例如Array,Map;复合类型:Class,Struct,Trait。符合类型是构成Atlas元数据类型的基础,元数据类型正是以复合类型为superType,继承其结构和属性,对业务系统的元数据进行建模。


在复合类型基础上构建起来的Atlas元数据类型,刻画了业务系统元数据的各个方面。元数据从功能上分,有数据元数据和计算元数据,数据元数据继承一般继承子DataSet预定义类型,计算元数据类型一般继承自Process元数据,Atlas的血缘关系正是对Process的输入输出链(数据元数据)进行分析的结果。值得一提的是,就存储本身而言,数据元数据和计算原数据并无差别。


下图给出了当前元数据项目里的部分元数据类型继承关系:

图中不难看出,一个元数据类型包含一个属性集合,这些属性可以是原生类型如string等,也可以是其他的复合类型如struct或其他元数据类型,如tencent_appgroup类型的product字段是另外一种元数据类型tencent_product。


类型系统构成了元数据模型的基石,具体的一条元数据必须复合类型的schema约束,正如关系数据表中的一行数据必须遵守表schema约束一样。


Atlas图存储结构

Atlas中所有数据均采用图存储,包括上文介绍的类型信息schema和具体的元数据实体,目前是janusgraph实现。可以预见,atlas的所有数据最终都会转换成图存储中的顶点vertex、边edge和属性property三种元素。在腾讯内部的元数据系统中,janusgraph以hbase作为落地存储服务。


众所周知,hbase采用列存储模型,其结构如下:


对janusgraph来说,需要将存储的三要素:顶点vertex、边edge和属性property转化为上面的模型。转化方式有两种:顶点切分和边切分。点切分即每个顶点转化为hbase的一行数据,顶点属性和关联此顶点的所有边均作为hbase的column存储在一行中。janusgraph正是采用了点分存储方式。点分示意图如下:

janusgraph存储模型转化后的结果如下图所示:


介绍到这里,我们知道Atlas元数据的schema、底层图存储的物理结构。下面介绍打通存储链路的最后一环,Atlas元数据类型到Janusgraph存储的映射。


Atlas元数据存储模型

Atlas在图中存储的数据分两大类:类型定义的存储和元数据的存储。类型定义信息是元数据的元数据,比如tencent_bg类型,描述了腾讯BG拥有的属性名称和类型清单。


类型定义模型

下面描述enum类型定义、struct类型定义、classification类型定义、entity类型定义以及relationship定义对应的janusgraph图顶点信息。


  • enum类型定义(enumDef)

vertex属性__type="typeSystem"__type.category=TypeCategory.ENUM__type.name=具体的类型定义名称如file_action__type.description__type.servicetype=服务类型如file_system__type.version__guid__createdBy=创建者的用户名__timestamp__modifiedBy=更新者的用户名__modificationTimestamp=修改时间__version__type.options#会为每个enum element生成下面两行属性__type.${typeName}.${enumValueName}=${ordinal} #如__type.file_action.READ_WTITE=6__type.__type.${typeName}.${enumValueName}.description=某个具体enumvalue的描述信息__type.${typeName}=所有的enum element值 #如__type.file_action={"NONE","EXECUTE","WRITE","WRITE_EXECUTE","READ","READ_EXECUTE","READ_WRITE","ALL"}__type.${typeName}.defaultValue=enum的默认值 #__type.file_action.defaultValue

(左滑查看完整代码,下同)


  • struct类型定义(structDef)
#vertex属性__type="typeSystem"__type.category=TypeCategory.STRUCT__type.name=具体的类型定义名称如file_action__type.description__type.servicetype=服务类型如file_system__type.version__guid__createdBy=创建者的用户名__timestamp__modifiedBy=更新者的用户名__modificationTimestamp=修改时间__version__type.options#会为每一个attribute生成下一行属性__type.${typeName}.${attrName}=json(AtlasAttribute)__type.${typeName}=List<属性名称>#对于每个非builtin类型的attribute,建立一条边,edgeLabel为:__type.edge.${typeDefName}.${attriDefName}


  • classification类型定义(classificationDef)
vertex属性__type="typeSystem"__type.category=TypeCategory.CLASSIFICATION__type.name=具体的类型定义名称如file_action__type.description__type.servicetype=服务类型如file_system__type.version__guid__createdBy=创建者的用户名__timestamp__modifiedBy=更新者的用户名__modificationTimestamp=修改时间__version__type.options#会为每一个attribute生成下一行属性__type.${typeName}.${attrName}=json(AtlasAttribute)__type.${typeName}=List<属性名称>vertex边#对于每个非builtin类型的attribute,建立一条边,edgeLabel为:__type.edge.${typeDefName}.${attriDefName}__type.supertype #为每个superType建立一条边__type.entitytype #为限定可以打标签的entityTypeDef建立一条边


  • entity类型定义(entityDef)
vertex属性__type="typeSystem"__type.category=TypeCategory.ENTITY__type.name=具体的类型定义名称如file_action__type.description__type.servicetype=服务类型如file_system__type.version__guid__createdBy=创建者的用户名__timestamp__modifiedBy=更新者的用户名__modificationTimestamp=修改时间__version__type.options#会为每一个attribute生成下一行属性__type.${typeName}.${attrName}=json(AtlasAttribute)__type.${typeName}=List<属性名称>vertex边#对于每个非builtin类型的attribute,建立一条边,edgeLabel为:__type.edge.${typeDefName}.${attriDefName}__type.supertype #为每个superType建立一条边


  • relationship定义(relationshipDef)
vertex属性__type="typeSystem"__type.category=TypeCategory.RELATIONSHIP__type.name=具体的类型定义名称如file_action__type.description__type.servicetype=服务类型如file_system__type.version__guid__createdBy=创建者的用户名__timestamp__modifiedBy=更新者的用户名__modificationTimestamp=修改时间__version__type.options#会为每一个attribute生成下一行属性__type.${typeName}.${attrName}=json(AtlasAttribute)__type.${typeName}=List<属性名称>endDef1=json(AtlasRelationshipEndDef)endDef2=json(AtlasRelationshipEndDef)relationshipCategory=RelationshipCategoryrelationshipLabeltagPropagation#边edgeLabel<为每一个endDef对应的顶点建立一条边,若两个endDef是同一个类型,则只建立一条边>__type..relationshipType


元数据实体图模型

元数据实体是指一种具体元数据类型的实例,比如一张具体的tdw hive表信息,或者一个具体BG信息。原始的信息以Json格式存在,后被转化为图存储模型。一个tencent_bg的json化数据如下:
{ "referredEntities": {}, "entities": [{ "typeName": "tencent_bg", "attributes": { "owner": "ls", "qualifiedName": "CSIG@tencent", "name": "CSIG", "description": "csig bussiness group" }, "guid": "-1234567890", "proxy": false, "version": 0 }]}


虽然具体的实体如thive表或tencent_bg携带不同的属性或引用关系信息,但是在底层图中存储却有相同的模型。转化为图中的vertex后具有以下存储模型:
vertex属性#每一个primitive类型的属性都对应下面的一个vertext property${entityType}.${attrName}每一个struct类型的Attribute对应一条边:连接entity vertex和该struct对应的vertex,edgeLabel为:__${entityType}.${attrName}每个objectId类型的Attribute,需要创建或更新对应的另一端顶点,然后更新两个顶点的边属性等信息对于每个Map类型的Attribute,若Map的valueType是primitive|enum|array|map类型,则直接生成一个vertexProperty;若Map的valueType是reference类型,则为每个value生成一条边,边的另一端对应这个mapvalue对应的顶点,边的属性__key=map的key对于每个array类型的Attritbue,若array的elementType为primitive|enum|array|map类型,则为entity的vertext生成一个property,${entityType}.${attrName}=array;若array的elementType为reference类型,则为每个element生成或更新对应的vertex,并生成一条边,边有个property:__index=element在array中的index对于classification的处理:1)把该classification的typeName加到vertex属性__traitNames中2)创建classification的vertex,属性包括: __typeName __state __timestamp __modificationTimestamp __createdBy __modifiedBy __superTypeNames __entityGuid __entityStatus __validityPeriods __propagate __removePropagations 为父类structType里的每个Attribute添加一个vertext property3)为entity和classification建立一条边,edgeLabel为classifiedAs,属性: __state=active __timestamp __modificationTimestamp __createdBy __modifiedBy __name=classfication的typeName __isPropagated4)查找该entity的所有具有传播关系的relation 对端vertex(比如table到包含的各种列),然后为每个传播vertex建立到classification vertex的边,并为该传播vertex添加属性值__propagatedTraitNames5)重新生成entity以及传播entity的fulltext字段entityText(包括entity所有属性和classification的属性),并通知EntityChangeListenerV2处理


Atlas类型解析

Atlas中的类型是是可扩展的,开发人员通过简单的Json格式的类型定义描述,就可以实现新的类型。正是具有扩展性,Atlas需要对所有的类型信息进行解析校验,只有通过解析校验的类型,才是符合Atlas元数据管理规范的,这也是上面所有存储模型能成功落地到图数据库的前件。


解析校验最重要的逻辑是检查类型所有原生类型属性是否符合schema要求、所有引用类型的属性是否在现有图中已定义。其实整个resolve过程简单来看,围绕2方面进行:


  • 属性,包括继承父类属性,解析属性的constraint,以及添加relationship中定义的属性到entityType中;当然会处理relation中边的label和direction等关系

  • 类型继承,填充各种superType和subType


具体来说整个解析校验过程分3个阶段,下面分别介绍之。


  • 解析phase1
AtlasStructType 校验所有attribute: cardinity为LIST或SET时,attribute类型必须为Array、 attribute类型不能为AtlasClassificationType、 attribute constraint:ownedRef指向的AtlasEntityType必须存在;inverseRef正反向对应的entity必须存在,即指向的AtlasEntityType必须存在,而且指向的AtlasEntityType必须有对应的属性指向自己 收集allAttributes和uniqAttributes(即attributeDef中字段isUnique=true的属性)AtlasEntityType 做父类AtlasStructType的resolveReferences 收集allSuperTypes,superTypes,headerAttributes(包括ENTITY_HEADER_ATTRIBUTES和ENTITY_HEADER_ATTRIBUTES_TDW),minInfoAttributes(包括所有的headerAttributes和schema-attributes)
AtlasClassificationType 做父类AtlasStructType的resolveReferences 校验superType必须为AtlasClassificationType 收集superTypes、allSuperTypes、allAttributes、uniqAttributes
AtlasRelationshipType 做父类AtlasStructType的resolveReferences 校验endDef12必须均为AtlasEntityType endDef1、endDef2不能指定cardinity=LIST,不能同时为container、有一个end为containetr时,关系类型不能为RelationshipCategory.ASSOCIATION, 类型为COMPOSITION和AGGREGATION时,必须有一个end是container


  • 解析phase2
AtlasStructType 对constraint为inverseRef的Attribute,设置Attribute的字段inverseRefAttribute=指向的entity的AttributeAtlasEntityType 做父类AtlasStructType的resolveReferencesPhase2 为所有父类填充subTypes、allSubTypes、typeAndAllSubTypes,即把当前正在解析的entityType加入到所有父类的subTypes集合中AtlasClassificationType 做父类AtlasStructType的resolveReferencesPhase2 为所有父类填充subTypes、allSubTypes、typeAndAllSubTypes,即把当前正在解析的entityType加入到所有父类的subTypes集合中AtlasRelationshipType 做父类AtlasStructType的resolveReferencesPhase2 确定relationship的edgeLabel: 1)endDef1和endDef2的isLegacyAttribute字段均为false,则edgeLabel=r:${relationName} 2)endDef1 isLegacyAttribute字段为true,则edgeLabel=__${endDef1TypeName}.${endDef1Name} 2)endDef2 isLegacyAttribute字段为true,则edgeLabel=__${endDef2TypeName}.${endDef2Name} 补充endDef1、endDef2两端对应Attribute(可能需要创建)的字段relationshipLabel,并把Attribute添加到end对应entity的relationshipAttributes,补充attrName-->relationType的映射 确定relationship的edge direction: 1)endDef1==endDef2,即对应的entityType和name均相等,则设置两端entity的Attribute的relationshipEdgeDirection=BOTH 2)endDef1和endDef2的isLegacyAttribute字段均为true,则两端entity的Attribute的relationshipEdgeDirection=OUT 3)若只有一个endDef的isLegacyAttribute=true则该端relationshipEdgeDirection=OUT,对端relationshipEdgeDirection=IN 4)两端isLegacyAttribute=false,则endDef1的relationshipEdgeDirection=OUT,endDef2的relationshipEdgeDirection=IN


  • 解析phase3


AtlasEntityType 对于Attribute类型为另一种EntityType,但是没有定义相应的relationship,则打印警告信息 把所有superType的relationshipAttributes添加到当前entityType的relationshipAttributes中
AtlasClassificationType 把所有的superType允许的entityTypes取交集,得到superTypeEntityTypes;获取当前classificationType允许的entityTypes,记为classificationDefEntityTypes 1)若没有superType,则entityTypes=classificationDefEntityTypes 2)若superTypeEntityTypes isEmpty,则抛异常 3)若classificationDefEntityTypes isEmpty,则entityTypes=superTypeEntityTypes 4)若superTypeEntityTypes不包含classificationDefEntityTypes,则抛异常 5) entityTypes中所有entityType的subType同样会被加入entityTypes中


结语

本文介绍了Atlas元数据系统的存储模型,分别从Atlas架构,类型系统,图存储结构,类型定义和实体的图模型以及类型解析等方面展开。希望通过这篇文章,使大家对Atlas元数据存储模型会有更深的了解。


推荐文章:

基于Hive进行数仓建设的资源元数据信息统计

元数据管理在数据仓库的实践应用

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存