只有一个 st 库的混沌期
没有 ETL 工具,没有工作流的概念(或者说所有任务就是一个工作流),没有调度平台,当然更不会有数据字典和血缘关系了。
所有的数据处理任务都是用 python 写的,SQL 自然也就都作为字符串写在 python 文件里了。在一个大 python 项目里,任务之间的依赖关系,则是维护在一个配置文件里的。
数据仓库分层架构图
(1)ODS 落地层 落地层 (Staging Area) 最初是作为介于业务源数据和数据仓库 ETL 之间的缓冲区而存在的。在 Hive 里它表现为一个独立的库,所有来自业务方的表都会先落到这个库里。 有赞的 ODS 落地层解决了两个问题:1)导表的冲突,2)落后的数据仓库中间层建设和日益增长的业务需求之间的矛盾。 导表的冲突由于数据源有各种各样的库,源表表名重复是很正常的情况。因此我们需要给每个表加上主题域前缀,从而避免来自不同主题域的同名表之间的冲突。当同一主题域下出现同名表时,我们辅以额外的表后缀来区分。 落地层解决了统一导表的落地问题,也承担着全局 ETL 中的第一轮 Extract。我们的原则是使落地层里的数据和业务数据保持一致,这也是为了方便将来数据问题的排查与核对。 数仓建设和业务需求之间的矛盾当时我们的人力完全无法满足众多需求方对数据的需求——数据中间层的建设赶不上飞速奔跑的业务需求。于是,一个折中的方法是让业务方直接使用落地层,自行处理一些不跨主题域的需求。 这里有业务方非常熟悉的原始表,他们能非常迅速地获得所需要的数据。这也有利于快速、低成本地进行一些数据方面的探索和尝试。 (2)DW 数仓层 数据仓库层在 Kimball 的数据仓库架构中应该映射的是数据展现层 (Presentation Area),它承载了最复杂的 ETL 逻辑和建模,也是维度建模集中体现的一层。 分层的误区Kimball 并没有对它做更细的层级划分。我们则依样画葫芦,根据当时业界较为通行的做法将整个数仓层又划分成了 dwd、dwb 和 dws 三层。然而我们却始终说不清楚这三层之间清晰的界限是什么,或者说我们能说清楚它们之间的界限,复杂的业务场景却令我们无法真正落地执行。 由于缺乏维度层,我们的维表显得无处安放;由于缺乏临时层,我们的中间结果和对外发布的表混在了一起。最终,三级分层只完成了我们的数据流向规范——从 dwd 到 dwb 再到 dws,层级之间不可逆向依赖。 宽表的误区 带着大数据环境下维度建模是否依然适用的疑惑,我们和许多人一样,在数仓层开始引入了宽表。所谓宽表,迄今为止并没有一个明确的定义。通常做法是把很多的维度关联到事实表中,形成一张既包含了大量维度又包含了相关事实的表。 宽表的使用,有其一定的便利性。使用方不需要再去考虑跟维度表的关联,也不需要了解维度表和事实表是什么东西。 但是随着业务的增长,我们始终无法预见性地设计和定义宽表究竟该冗余多少维度,也无法清晰地定义出宽表冗余维度的底线在哪里。 一个可能存在的情况是,为了满足使用上的需求,要不断地将维表中已经存在的列增加到宽表中。这直接导致了宽表的表结构频繁发生变动。 (3)DM 数据集市层 数据集市层 (Data Mart) 根据主题域的不同在物理上进行划分——它表现为多个相互独立的库,各个数据集市之间不允许做数据依赖。每个数据集市可以由该主题域的使用方在数据仓库规范下自行开发和建设。 这一层可以根据使用习惯,建立一些宽表。但是如果要配合 Kylin 使用的话,依然建议保持星型模型——它能最大限度的发挥 Kylin 预聚合的优势。| 任务优先级 | 使用规范 |
| P1 | 涉及资损DW任务关键路径优先级 |
| P2 | 重要DW任务关键路径优先级 |
| P3 |
DW任务关键路径优先级 |
| P4 | DW任务非关键路径优先级/非DW任务关键路径 |
| P5 | 非DW任务非关键路径(默认) |
数仓任务优先级规范
| 比较点 | 维度建模 | 宽表 |
| 扩展性 | 维度表变更,事实表可能不影响 | 维度变更可能导致很多宽表都要调整 |
| 耦合度 | 事实表和维度表解藕,某些粒度上不会因为维度表失败而影响聚合表的产出 | 一个非重要任务失败会导致整个宽表无法产出 |
| 组织方式 | 任务及工作流易组织 | 因高耦合导致任务之间盘根错节,不利于组织任务和工作流 |
| 数据一致性 | 企业级数据仓库总线架构的基石 | 底层如果没有维度建模支撑,容易陷入混乱 |
| 易用性 | 维表需要多几个维表关联 | 宽表一时爽 |
Kimball早期的数仓架构
Kimball后期的数仓架构
这个转变与我们的理念不谋而合:从业务层面看,数据仓库的核心是展现层和提供优质的服务。ETL 及其规范、分层等所做的一切都是为了一个更清晰易用的展现层。 数仓层内部的划分不是为了分层而分层,它是数据仓库经过了建模和 ETL 之后真正开始对外提供服务的地方,因此数仓层内的划分更应该符合使用者的思维习惯。DW 内的分层没有最正确的,只有最适合你的。 基于维度建模的总线架构 (Bus Architecture) 理论,承载一致性维度 (conformed dimension) 的维度层是独立于事实并贯穿于数仓层全局的。 除此之外,我们提供了两种类型的事实表:明细表和聚合表。因此在我们的数仓层里,还会有明细层和聚合层。我们为明细层保留的关键字是 DWS (Data Warehouse Service),从这里开始,我们的表要承担起对外提供服务的职责。我们为聚合层保留的关键字是 DWA (Date Warehouse Aggregation)。 在大数据环境下,我们并没有按照 Kimball 的理论,显性地将事实表按照事务 (Transaction)、周期快照 (Periodic Snapshot) 和累积快照 (Accumulating Snapshot) 三种类型来划分。尽管这三种类型普遍存在于我们的数据仓库内,但由于用户并不容易理解三种事实表类型的划分方式,因此按照明细表和聚合表的方式分层,更容易让用户找到需要的表。 最后,在我们生产明细表和聚合表的时候,不可避免地会产生许多中间结果。所有这些中间结果并不承担对外提供服务的职责——它们对数据仓库的使用者是不可见的。我们为此单独设计了一个临时层来存放数仓层加工过程中可能产生的各种结果。临时层是在 Hive 上额外开辟的一个数据仓库开发人员专用的库。它承担了数据生产过程中问题数据的跟踪,也是数据存储清理时优先考虑的一块空间。
新的数仓内部分层
| 分层数据库 | 表命名规范 |
| ODS 落地层 | 主题域_原表名[_可选的后缀] |
| 明细层 | dws_主题域[_可选的二级主题域]_相关描述 |
| 聚合层 | dwa_主题域_聚合维度 |
| 通用维度层 | dim_通用维度相关描述 |
表命名规范
这里的落地层可能有些人叫 stg 有些人叫 ods。具体叫什么并不重要,重要的是命名的规范能够迅速地在所有相关人之间达成共识——这不仅包括了数仓的开发人员,更需要考虑的是数仓的使用人员。最终的目的还是让使用者能够快速准确地找到他们想要的数据。 聚合表时间后缀的含义 我们经常会发现聚合表的后缀会出现 _di 或者 _df,这里的 i 和 f 表示增量和全量,而 d 表示天,但是却又总是说不清楚它究竟是表示天级别的聚合粒度还是每天运行一次的调度周期。 大多数情况下表的聚合粒度和它的调度周期是一致的,然而也确实存在例外的情况:你可能每天运行一个聚合到小时级粒度的数据,以观察每小时的走势。 站在使用者的角度来看,他并不关心表的调度周期,只在乎这个表的聚合粒度。而调度周期则是一个跟工作流强相关的属性。 同样地,除非这张表里只包含了增量部分的数据(此时我们会用 _incr 后缀),否则使用者依然不会关心该表是增量 ETL 还是全量 ETL 的。 所以我们尽量不将表使用无关的 ETL 信息暴露给使用者。在有赞,聚合表的时间后缀只表示该表的聚合粒度,与 ETL 的调度周期或处理方式无关。 (2)字段命名规范 同名同义性是我们对字段命名的首要要求。如果两个字段名字一样,那么它们的含义应该是一样的;反之,如果两个字段名字不一样,那么它们的含义就一定是要有区别的。当这个要求放在单个主题域内的时候,还是容易实现的。当它推广到全域范围内,这个事情就会变得有些困难。 其次,字段名称清晰是另外一个要求。良好的字段命名应当是自解释的,如果看完字段的注释还无法理解甚至曲解字段的含义,那个可以说这个字段的命名和注释是不合格的。
通过FineDataLink作为中间件,简道云数据下云本地化,原库用于提供业务负载,本地库搭配FineReport用于数据分析展示,解决了数据分析人员无法完全取到简道云数据的问题,在FineDataLink侧进行简单的配置,同步数据和附件,即可完成简道云数据的迁移。通过FineDataLink作为中间件,简道云数据下云本地化,原库用于提供业务负载,本地库搭配FineReport用于数据分析展示,解决了数据分析人员无法完全取到简道云数据的问题,在FineDataLink侧进行简单的配置,同步数据和附件,即可完成简道云数据的迁移。
整合了MES、ERP、SQS、APS、PLM等系统,建立了公司级别的数据仓库,统一数据源,统一数据分析出口。
FineDataLink和6节点的FineData相结合,自动把4个厂的MES、ERP、WMS、PLM等业务系统,通过数据库logminer、消息等进行实时采集同步;通过对ODS层的数据加工作转换进行分层建设,完成分布式数仓的搭建,10分钟内即可完成从业务库,到ODS的ELT的整个数据链条处理。