数仓设计指对数据仓库的各项组成进行规划,在正式建设数仓之前形成指导性建设方案。
数仓设计主要分为两部分:数据仓库同操作型业务系统的数据接口设计和数仓自身建设设计。
本文从多个方面探讨数仓的设计要点,给出需要注意的问题,提供部分实践建议。
体系结构从整体描述数仓,是数仓的数据架构,包括数据导入、ETL、数仓建设、OLAP引擎以及数据的最终使用。
上图是一个典型的数仓体系结构。源数据经过ETL,在数仓中建设存储,被下游分析使用。元数据则被用来说明数据、管理数据。
整个体系中,包括数据的抽取、模型建设、数据加工、数据导出、数据服务以及数据的生命周期管理,这些数仓设计要素将在下文中详解。
含义
粒度指数仓中数据的细节程度或综合程度的级别,通俗讲是表中每行代表的含义。Bill Inmon认为粒度是数仓设计中最重要的设计问题,这点让我有些意外,但是看完他的解释也就理解了。粒度不仅影响数仓数据量的大小,还决定数仓的查询能力以及查询性能。
粒度可以分为低粒度和高粒度,低粒度是指保存了所有数据细节,高粒度则忽略部分细节,对数据做一定聚合。
示例
比如,某通信运营商希望存储用户的通话记录。
如果用户每次通话记录在表中存储一行,每行保存用户的通话时长、通话开始/结束时间、被叫人、主叫地点、被叫地点、通话费用,该方式保存用户通话的明细,属于低粒度的保存方式。
另一种保存用户每天的通话记录,每行存储用户当天通话次数、总通话时长、总通话费用等,该方式针对用户当天的通话记录做适当的聚合汇总,称为高粒度的保存方式。
优缺点
在低粒度存储方式下,数仓能满足所有的查询需求,比如“查询某用户在某日的被叫次数”。
但是由于保存所有明细数据,整张表较大,数据查询性能损耗高且响应速度相对较慢,如统计某个月的合计通话时长,需要将该月所有的通话记录做聚合计算。
高粒度存储下,能较快响应部分需求,如“统计某个月的合计通话时长”。
由于已经提前汇聚每个用户的每日通话时长,只需将30天的数据累加即可。计算量相对低粒度方式,减少数倍以上。
高粒度数据针对部分请求无法满足,比如上文提到“查询某用户在某日的被叫次数”。
二者对比:
分类 | 低粒度 | 高粒度 |
效率 | 低 | 高 |
访问灵活度 | 低 | 高 |
回答全部问题能力 | 是 | 否 |
回答全部问题能力是指能否满足用户所有的合理的查询需求,比如上文提到“查询某用户在某日的被叫次数”。
最佳实践
数据双重/多重粒度级是建设数据仓库细节级最好的体系化结构选择。
双重粒度是指数仓既保存低粒度细节数据又保存高粒度汇总数据,多重粒度是双重粒度的优化,在双重粒度按天汇聚的基础上,增加按月/季度/全部时间等方式的汇聚。
通常情况下,95%的访问请求访问高粒度数据,剩下5%的情况必须访问低粒度细节数据才能得到结果。大部分的请求访问高粒度数据,数据量小且存取效率高。小部分的访问需要访问明细数据,麻烦、复杂且成本昂贵。
多重粒度下,数仓同时具备高效率访问和回答全部问题能力的优点。
目前多重粒度已经成为主流数仓粒度方案,阿里的《大数据之路》书和网上众多教学视频中提到的dwd/dws/dwt等层,也是多粒度的设计理念。
关于维度建模中数据粒度,Kinball在《维度建模工具箱》一书给出建议:事实表总是选择最细粒度的数据,即低粒度存储方式。
针对数据汇总,计算出一组数据的最大/最小/平均值,都是建设高粒度数据的有效方式。
分区指把数据分散到可独立访问理或更新的分离物理单元/目录中。
以用户通话记录表为例,假设有2天的数据记录:‘2022-03-23’和‘2022-03-24’两天的通话记录,23号的通话记录存储在目录1中,24号的通话记录存储在目录2中。对23号的数据计算时,只需要读取目录1中数据,减少了数据的处理量。
大数据领域,分区功能非常重要。实际工作体验中,分区几乎是最简单也最有效的性能优化手段。如果做到合理分区和有效分区剪裁,性能优化就做到了事半功倍。常见大数据计算引擎Hive和Spark对于分区的支持非常完善。
分区优点:
分区标准
实践
维度表:针对数据量不大的维度表,分区保存。比如每天一个分区,每个分区包含全量信息。在占用存储空间不大的情况下又保留跟踪维度变化的能力。对外提供只能访问最新分区的视图供下游使用。
事实表:针对大数据量的事实表,推荐总是采用分区的方式存储。在模型设计和ETL上多花点精力,实现事实表的分区增量存储。非增量存储的大型事实表对于下游使用将是灾难。
在后期数据治理过程中,通过设置分区生命周期,自动回收过期的分区数据,减少数据的存储空间。回收策略参考文末附录1。
还可以针对分区做进一步的治理优化。如某大型事实表存有近3年的分区数据,通过元数据梳理发现部分程序每日访问全量分区或最初几个月的分区。由于事实表本身是增量分区设计,通常情况下无需访问很早的历史分区,因此可以考虑对下游进行优化。
数据处理过程中,分区剪裁是否生效,在实际业务中也值得关注。大型事实表的分区过滤如果没有生效,对性能影响非常大,在性能优化时应该留意这块,更多参考文末附录2。
定义
生命周期是指数据从产生至最终销毁/归档的整个过程,包括:
其中黄色部分发生在业务库中,绿色部分发生在数仓使用过程,红色部分为数据治理过程。
如果数据没有遵守这个流程会怎么样?答案是数据将只进不出,在大数据场景下,存储快速膨胀,集群成本增长大于业务增长。
数据生命周期管理,是数仓存储管理中最有效的手段,应当被重视。
实践
在用户建表时,需强制用户指定表生命周期。如果是分区表,必须设置分区类型是全量还是增量,并针对分区设置生命周期。
应当收紧用户建表的口子,并在建表引擎底层语法层面进行生命周期约束,确保任何允许建表的方式下都执行该约束。
表或分区的生命周期到期前及时提醒用户,生命周期到期后进行回收处理。
针对ods层也就是业务系统进入数仓的数据,通常不会主动删除这部分数据,不论是作为业务库的备份还是从下游数据恢复角度考虑。导入数据到期后进行冷备归档。
针对下游加工数据,到期后移至回收站,使数据不可访问,并在一定时间后(如2周)彻底删除数据,在彻底删除之前仍保留数据恢复正常使用的能力。
生命周期是元数据的重要组成,应当利用元数据定期检查生命周期设置合理性,避免用户设置不合理的生命周期。
规范化是数仓之父Inmon推崇的数仓模型设计方法,通俗理解为模型设计符合第三范式。
逆规范化则相反,包含数据冗余、表合并等,典型的实现为维度建模理论中星型模式,由Kinball提出。
关于两种设计方法的对比参考附录3。
逆规范化设计在大数据时代互联网领域更加流行,主要原因:
规范化设计在传统行业仍具有价值,原因:
常见的拟规范化设计方法:
数仓常见的两种模型设计方法:关系模型和多维模型。
关系模型由Inmon提出,遵循规范化设计;多维模型由Kinball提出,典型由星型模式,采用维度和事实设计,为逆规范化设计。
关于两种理论,本文不深入讨论,Inmon和Kinball都出了书,分别为《数据仓库》和《数据仓库工具箱 维度建模权威指南》,有兴趣的读者可以读一读。
附上特性比较:
特性 | 星型模型 | 关系模型 |
数据摄取 | yes | yes |
stage | yes | yes |
ETL | yes | yes |
数据集市 | yes | yes |
商业需求 | yes | yes |
数据时间属性 | yes | yes |
数据仓库优先 | no | yes |
事实维度拆分 | yes | no |
关系表维护 | no | yes |
处理导向 | yes | no |
数据模型泛化 | no | yes |
精心设计 | no | yes |
缓慢变化维 | yes | no |
连续变化维 | no | yes |
应用场景对比:
特性 | Kimball | Inmon |
时间 | 快速交付(几天至几个月) | 建设周期长(几个月至几年) |
开发难度 | 小 | 大 |
维护难度 | 大 | 小 |
技能要求 | 入门级 | 专家级 |
使用对象 | 部门级 | 企业级 |
更多的对比请参考附录3。
模型开发
在实际工作中,如何实现规范化模型建设,请参考附录4美团外面团队的实践。
文中提到数据工程师从业务方接收需求后的工作流程:
为防止随意建设,造成模型混乱导致数据一致性问题,通常会指定许多规范和管理措施。
如维度管理平台、指标定义平台、主题域管理等平台,规范方面有模型设计规范、ETL开发规范、命名规范、数据标准等。更多的平台管理和规范,可以参考阿里的dataworks平台,见附录5。
实践
模型建设完成后,后期管理也很重要。
当模型需要更新时,应当注意模型修改后对下游的影响。对下游有影响的更改,如更改属性含义、字段类型等,必须提前通知下游,新增属性对下游无影响的可不通知。
还应当跟踪模型的使用频率。被大量下游使用的模型,通常是重要模型,需要设置为基线任务重点保障。
如果下游较少,考虑什么原因导致。如下游确实业务减少,这种情况下是否降低模型重要性和执行频率以减少资源消耗。还是由于模型设计不合理导致无法满足下游的需求,进而考虑优化模型。
当模型建设完成后,应当关闭原始层的数据访问权限,确保下游任务统一使用我们提供的模型。
模型开发效率、模型覆盖度、模型数据质量和稳定性、模型的文档描述和易用性,是数据开发同学能力的重要体现。
备份分类
数据分为频繁访问、不频繁访问、无访问三种情况,分别对应不同的存储方式。
通常情况下,频繁访问指每个月访问2-3次以上,不频繁访问大概是每两年访问一次。其他为无访问情况,如近3年无访问、生命周期过期的导入数据等。具体访问频率划分应根据实际数仓环境确定。
不同数据类型对应不同的存储。
频繁访问的数据存储在性能较好的磁盘中,提供快速访问能力。
不频繁访问的数据存储在一般性能的磁盘中,用户可以接受这种每两年一次的低效率访问。
不访问数据,即冷数据,将进行备份处理,数仓从数仓环境移至备份库中,数据不可访问。
备份存储
备份库存储器通常采用廉价存储,访问性能非常低或麻烦,可选存储介质有光盘、廉价磁盘、磁带等。
如果公司安全政策允许,也可以将冷备数据放在云服务商提供的对象存储 COS中,这类存储通常会比较便宜且管理方便。
还有其他方案,比如我们公司数仓集群运行在Hadoop2环境上,Hadoop3提供纠删码技术能将存储节约50%,我们运维同学利用部分机器搭建Hadoop3环境。归档数据相比原空间,占用存储节约一半。
一般的公司可能没有区分频繁和不频繁两种数据的存储方式,而是采用相同存储方式。我司就是这种情况,统一采用hdfs系统存储在性能相同的磁盘中。
选择不同存储时,应当考虑不同介质间的数据移动问题,如传输效率、传输软件支持。
用户访问
频繁访问数据和不频繁访问数据用户可以直接访问,冷备的数据用户无法直接访问。
对于用户来说,频繁访问数据和不频繁访问数据访问的接口是相同的,用户不需要知道二者底层存储的差异。
通常情况下冷备数据无需提供用户访问的接口,或者提供一个不是很便利的访问方式即可。
分布式数仓指不是只有一个全局数仓,而是有多个数仓。多个数仓间的关系,可能是局部和全局,也可能是相互独立。最近有个很火的概念“东数西算”,可能就涉及分布式数仓的理念。
分类
大型跨国公司的业务可能分布在全球多个国家,通常他们会有一个全球总部,然后在重点国家设分公司。比如字节跳动的全球总部在北京,旗下的Tiktok总部设在美国。
大的公司内部,通常有多个业务部/事业群。比如阿里集团,钉钉、菜鸟,在这些部门内部数仓可能是各自独立建设,也可能是统一的全局数仓。
从业务范围角度划分,可分为局部数仓和全球数仓。比如Tiktok在美国建设的只面向美国用户的数据分析服务,称为局部数仓;而北京总部的针对全球数据进行分析的数仓,称为全球的服务数仓。
从部门角度看,在组织或管理上相互独立的数仓称为部门级数仓,比如财务部门和供应链部门各自独立建设的部门级数仓。
实践
局部数仓存放局部的数据,可以从地理位置、业务等角度划分;在局部数仓中,涉及全局公共数据,最好放在全局数仓中,以保障数据一致性。
要特别注意局部数仓至全局数仓的数据映射问题。如Tiktok在北美的数仓中货币单位可能采用美元,北京的全局数仓货币单位为人民币,那么数据从局部数仓进入北京总部全局数仓时,需要将货币单位做对应映射处理,转换为人民币。
业务完全分离、非集成,相互间数据不共享的数仓可以由不同的小组独立建设。
不同小组也可以共同建设同一个数仓,每个小组负责数仓的不同部分。
不同小组共同建设数仓,可以从多个角度进行任务划分。如针对分层的数仓,不同的小组分别负责明细层、聚合层、应用层的建设;或者从主题域划分,不同小组承担不同主题域;或者同一个主题域下承担不同业务过程的数据建设。
多个小组共同建设数仓时也需要建设公用数据模型,已解决数据间的冗余和一致性问题。
技术难点
分布式数仓环境下需要考虑数仓间的数据传输问题,从性能、成本等角度综合选择数据传输技术。
还应当考虑数据传输的合法性。
闹得沸沸扬扬的特朗普要求Tiktok脱离字节公司掌管事件,本质上是因为美国政府担心tiktok中大量的美国用户数据信息传至总部在北京的字节公司数据中,可能最终会损耗美国的国家安全。最终字节将TikTok的数据存储至oracle数据中心,由oracle确保数据不会离开美国,才避免了字节被迫出售TikTok的结局。
数据跨境传输的合法性、遵守当地的隐私保护政策,是建立分布式数仓必须重点考虑的问题。
最后还应当考虑在局部数仓和全局数仓集成时,数据间的加载、转换和映射问题,确保数据的一致性。
非结构数据现在比较流行的方案是数据湖/湖仓一体的存储方式,感兴趣的可以了解对应的方案。
非结构化数据迁移至数仓后,针对图片、视频、文本,可从多个角度提取结构化信息,比如对应所属的主题、描述问题、关键字等。通过提取结构化信息,为后续数据分析做准备。
非结构化数据可以存储在数仓中,或者数仓保存非结构化的引用而数据存储在仓库外。
定义
数据抽取是数据在操作型环境中产生后,流转至数仓环境的过程。回流则反之,从数仓环境产生的数据流转至操作型环境。
操作型环境通常指业务系统中的关系型数据库,比如mysql。数仓环境指数仓存储系统,如hive。数据抽取是数据从mysql传输至hive,数据回流则是从hive至mysql。
抽取/回流原因
为什么要做数据抽取或回流,由两种数据处理系统的作用和特点决定。
从性能角度:
基于上述原因,当数据需要分析处理时,需要先抽取至数仓环境。一旦数据分析完成便提前回流至操作型环境中,以满足在线业务的实时访问需求。
除了性能原因,还涉及数据的控制权问题。
抽取数据将数据从操作型事务处理环境中抽取至数仓环境后,数据的控制方式发生了转变。最终数仓开始控制数据,最终拥有了抽取至数仓的这部分数据,后续进行分析处理才具有更多的权利。
如果数据一直保留在操作型事务处理环境中,数据分析者不可能拥有数据的全部处理权限。
数据抽取策略
首次抽取通常为全量数据抽取,后续根据实际情况制定抽取策略:
以上方式都支持全量抽取,目前使用最流行的是日志订阅方式。业界也有开源的框架实现数据抽取服务,比如canal、maxwell、datax等。
数据检查
除了选择抽取的数据,还应当关注不同系统间的数据格式转换问题,主要为日期类型格式转换。
数据抽取过程中,应进行脏数据检查,如取值范围、格式等校验数据有效性。并指定脏数据处理策略,是直接抛弃还是阻断下游,又或者设置脏数据阈值等。
数据回流
数仓的数据也可以提供直接访问方式,比如tableau报表服务可以直接联系hive访问数据。通常直接访问数仓时,响应时间较长并且访问数据量不宜过大。
外部服务对数仓的使用方式更多是数据先回流至外部高性能数据库中,再访问高性能数据库。这类数据库通常称为olap引擎,常见的有kylin、Apache doris,还有战斗民族性能爆表的clickhouse,此外,数据回流至非关系型数据库,如elasticsearch和hbase也比较常见。
不同olap处理特点不同,有擅长关系型计算,有擅长多维数据聚合操作,应根据实际情况进行选择。
数据集成指数据从不同操作型系统中进入数仓环境中数据的处理,属于ETL的重要环节。
集成内容
除此之外,还涉及不同数据源、不同系统的数据集成。
难点
业务系统通常缺乏针对数据的完善定义文档,或文档定义没有及时更新,导致数据开发人员无法掌握数据的准确信息。业务数据可能由于业务不规范,导致数据缺失、脏数据较多。这些因素将影响数据开发效率和质量。
数据集成后,应当符合数仓模型设计规范。比如根据维度建模建设的数仓,数据应当围绕维度表和事实表进行建设。
数据集成过程中,还需要考虑保存数据的历史变化。参考附录6,缓慢变化维度的设计实现。
数据标准
数据标准在字段的定义、命名、度量单位、取值范围、枚举、命名词典等方面给出定义和标准,是解决数据集成过程中数据一致性比较有效的方法。参考附录7,阿里云dataworks的数据标准实现方案。
数据速率指数据产生后,到能被分析人员使用的平均时间,也称为数据的时效性,是数据质量的一个重要部分。
数据速率最重要的影响因素是数据抽取的速率,即数据从操作系统进入数仓的时间间隔。
数据在ETL的效率以及链路的层级,也会影响数据的产出效率。
数据周期
操作型数据变化同步更新至数仓,称为实时更新;操作型数据变化间隔时间为分钟或小时级别,称为准实时更新;操作型数据变化第二天凌晨进入数仓环境,称为离线更新。
实时更新和准实时更新也称为T+0数据,离线同步的数据称为T+1数据。
影响因素
首先,待抽取的数据量越多,数据速率就越低。这是由于数据抽取传输的时间变大加上ETL处理时间更久导致;
其次,数据进入数仓后,数据链路的ETL效率也对数据速率影响较大;
最后,采用数据抽取的技术,如果采用日志订阅方式,数据可以实时抽取、实时写出。
实践
提高数据效率/及时性的方法:
现在普遍谈论数仓实时化、流批一体技术,表明业内对数据时效性更加关注。但是也应意识到,不应盲目追求数据时效性,原因:
当我们完成数仓设计后,应该思考以下问题,以检查数仓设计是否完整、全面。
本文讨论了数仓建设中的理论基础,涵盖数仓多个设计要点,整体内容偏理论化,少部分给出实践建议。
基于设计理论,我们才能制定建设规范,并在规范指导下建设数仓。
如果想要进一步了解完整的数仓实现,推荐大家阅读阿里dataworks的帮助文档,附录8。
附录: