本系列包含:
前面已经解读实时数仓的背景、技术线路和应用场景,这里具体从实现的角度来介绍实时数仓。
在介绍实时数仓之前,我们先看看离线数仓的标准架构。众所周知,离线数仓一般分为 ODS(Operational Data Store)、DW(Data Warehouse) 和 DM(Data Market) 三层架构,这里面的 ODS 就是数据接口层,目前逐步被数据湖的概念取代,但是其基本原理没有变化,主要是 数据同步方法、数据存储方式 和 增量数据获取 等方面有所加强。往上 DW 层就是数据仓库层,也是我们离线数据处理和模型设计的核心,现在通用的分层都是分为 DWD(Data Warehouse Detailed)、DIM(Dimension)、DWS(Data Warehouse Service) 三个模块,DIM 加工一致性维度;DWD 保留业务模型数据并进行数据格式规范化、字段命名标准化;DWS 聚焦指标逻辑加工,并适当进行数据汇总,减少数据量。有时候我们还会在 DWS 层的基础上增加 DWT(Data Warehouse Topic),作为宽表,但是我们也可以将这一层保留在 DWS 中,作为 DWS 层的一部分。DM 层是数据集市层,在 OLAP 查询不理想的情况下,DM 层是需要大力建设的。现在技术发展了,OLAP 查询不再是瓶颈,我们将建设的重心下移到提供一致性对外数据服务的 DWS 层,DM 层的开发工作逐步减少。
以我目前负责的电商业务为例:
从离线数仓过渡到实时数仓,我们的基本数仓分层没有变化,只不过为了数据时效性,有时候会省掉其中一些计算步骤。
实时数仓的设计理念主要由两个思路:Lambda 架构和 Kappa 架构。
Lambda 架构是由 Twitter 工程师南森·马茨( N a t h a n M a r z Nathan\ Marz Nathan Marz)提出的。Lambda 架构简单的说就是流式数据作为批处理的补充,流数据之加工当日实时数据,批处理更新当日及之前的数据,在数据应用层将二者加工的结果合并起来。
Kappa 架构可以认为是 Lambda 架构的简化版,即移除 Lambda 架构中的批处理部分。在 Kappa 架构中,需求变更或历史数据变化都通过上游重放完成,即回溯数据进行重算。
Lambda 架构提倡实时数据流程处理当日数据,T+1
数据用离线加工来回补和修正,具有很好的灵活性和可扩展性,也对硬件故障和人为失误有很好的容错性。由于有批处理作为后盾,实时数据加工的压力大大减轻;由于有了离线数据加工,数据的准确性也得到了保障。
Kappa 架构最大的优点是仅需一套代码,可以同时完成流式数据加工和批量数据加工,最大的问题是批量数据加工的能力会低于离线批处理,因此历时数据的回溯时长存在不确定性。
目前大部分都是采用 Lambda 架构,也有不少企业在尝试 Kappa 架构。从设计上说 Kappa 架构肯定是更优的,一套逻辑处理增量和全量,但是实际上比较难实现,或者说实现代价非常高。
要比较两种方案那种更好,我们需要先思考下面四个问题:
前面我们介绍了 Doris 具备强大的 多表关联查询能力 和 基于主键的数据增删改能力。所以我们不妨结合流数据和 Doris 强大的查询能力来构建流批一体方案。简单的说就是底层逻辑用流数据写入,上层逻辑通过 SQL 关联来实现。
基于对以上四个问题的思考,我提出了基于 Doris 的全新实时数仓方案,也就是 流 + 批 组合模式。按照流数据加工的层级和批数据加工层级不同,分为了五种具体方案。
方案一 | 方案二 | 方案三 | 方案四 | 方案五 | |
---|---|---|---|---|---|
ODS | 流式写入 | 保留副本 | 保留副本 | 流式写入 | 保留副本 |
DWD | 微批加工 | FlinkSQL 写入 | 保留副本 | 视图 + 隔日刷新 | FlinkSQL 写入 |
DWS | 微批加工 | 微批加工 | FlinkSQL 写入 | 视图 + 隔日刷新 | 视图 + 隔日刷新 |
ADS | 可忽略 | 可忽略 | 可忽略 | 可忽略 | 可忽略 |
方案一是流数据写入 ODS,往上数据加工逐层进行微批处理,在保证数据准确的情况下,提高微批的频率。
我们可以通过 Flink 清洗 Kafka 日志数据写入 Doris、Doris 直接读取 MySQL Binlog、Doris 直接读取 Kafka 日志数据 三种方式实现 ODS 层的数据实时接入和实时更新,往上可以通过半小时一次或者更高频率的跑批任务刷新数据到 DWD、DWS、ADS。
方案二是用 FlinkSQL 完成 DWD 层数据清洗和表关联,将数据写入 DWD 层,往上逐层进行微批处理。
我们通过 FinkSQL 读取 Kafka 数据后,利用 FlinkSQL 的 ETL 能力,将数据依次加工成 DWD、DWS,然后写入 Doris,在 Doris 中通过报表直接查询 DWS 的数据,完成数据的实时展现。
方案三是 Flink 完成 ODS 到 DWD、DWD 到 DWS 的数据加工,并将数据同步写入 Kafka 和 Doris,Doris 只做数据查询,不进行数据加工。
需要通过 FinkSQL 完成数据的全流程加工,直接将 ADS 层的数据写入 Doris,由分析平台直接读取结果展示数据。
我们还可以针对路径一和路径二进行优化,将 ODS 或者 DWD 层往上的数据加工替换成视图,然后由数据分析平台直接查询顶层的视图,这样就衍生出了方案四和方案五。方案四和方案五的优点是不需要跑批,可以直接查询最实时的数据,缺点是如果代码过于复杂,会影响前端查询性能。
方案四是将方案一中的数据微批处理改成视图,流批用同一个程序,T+1
数据写入实体表,实时数据写入 ODS 后通过视图获取,对外提供实体表 union all
视图的数据给查询使用。
方案五是将方案二的微批处理改成视图,实时数据写入 DWD,往上利用视图查询当日数据,T+1
数据每日刷新写入实体表。
这五种方案简单实用,虽然无法构建完整的流批一体数仓,但是可以满足大部分实时数仓的需求。之所以提供五个方案,主打一个灵活。
听到这里,可能很多朋友会说,切,你这太简单了吧?这里我会说,简单不好吗?Flink 搞得那么复杂,数据准确性和运维便捷性能超过这五个方案吗?做数仓开发,我从来都崇尚 大道至简,逻辑非常简单都可能会出现 Bug,搞得太过复杂 Bug 不是更多吗?
最后我们再对比一下这五个方案:这五个方案各有优点,也各有缺点,不能简单的说哪个好,哪个不好。各有不同的应用场景:
以上五个方案都可以实现实时数据和离线数据加工共用一套代码逻辑,降低维度成本,实现了某种程度上的流批一体。
最后,我们再回到前面介绍的八种实时数据的应用场景,根据业务场景的不同,对数据时效性和准确性的要求也不同。
业务场景 | 方案一 | 方案二 | 方案三 | 方案四 | 方案五 |
---|---|---|---|---|---|
监控预警 | ✔️ | ✔️ | |||
实时大屏 | ✔️ | ✔️ | |||
机器人播报 | ✔️ | ✔️ | |||
移动看板 | ✔️ | ✔️ | |||
自助分析 | ✔️ | ✔️ | |||
实时看板 | ✔️ | ✔️ | |||
实时接口 | ✔️ | ✔️ | |||
实时推荐 | ✔️ | ✔️ |