基于Flink+Hive+Kafka的流批一体数仓实践--01架构及思想

基于Flink+Hive+Kafka的流批一体数仓实践–01架构及思想

最近阅读了李劲松老师的一篇文章,决定基于他的思想实践一把。
为什么需要实时数仓?
基于 Hive 的离线数仓往往是企业大数据生产系统中不可缺少的一环。Hive 数仓有很高的成熟度和稳定性,但由于它是离线的,延时很大。在一些对延时要求比较高的场景,需要另外搭建基于 Flink 的实时数仓,将链路延时降低到秒级。但是一套离线数仓加一套实时数仓的架构会带来超过两倍的资源消耗,甚至导致重复开发。
想要搭建流式链路就必须得抛弃现有的 Hive 数仓吗?并不是,借助 Flink 可以实现已有的 Hive 离线数仓准实时化。
离线数仓架构的问题:基于Flink+Hive+Kafka的流批一体数仓实践--01架构及思想_第1张图片

上图是一个典型的离线数仓,假设现在公司有一个需求,目前公司的数据量很大,需要每天出一个报表且输出到业务数据库中。首先是刚入库的业务数据,大致分为两种,一种是 MySQL 的 binlog,另外一种是业务系统中的业务打点,这个日志打点信息可以通过 Flume 等工具去采集,再离线入库到数仓中。然后随着业务越来越多,业务中的各个表可以做一些抽象,抽象的好处是更好的管理和更高效的数据复用和计算复用。所以数仓就分成了多层 (明细层、中间层、服务层等等),每一层存的是数据表,数据表之间通过 HiveSQL 的计算来实现 ETL 转换。
不止是 HiveSQL ,Hive 只是静态的批计算,而业务每天都要出报表,这意味着每天都要进行计算,这种情况下会依赖于调度工具和血缘管理:
调度工具:按照某个策略把批计算调度起来。
血缘管理:一个任务是由许多个作业组合而成,可能有非常复杂的表结构层次,整个计算是一个非常复杂的拓扑,作业间的依赖关系非常复杂 (减少冗余存储和计算,也可以有较好的容错),只有当一级结束后才能进行下一级的计算。

当任务十分庞大的时候,我们得出结果往往需要很长的一段时间,也就是我们常说的 T+1,H+1 ,这就是离线数仓的问题。

实时数仓架构:
基于Flink+Hive+Kafka的流批一体数仓实践--01架构及思想_第2张图片
实时数仓其实是从 Hive+HDFS 的组合换成了 Kafka,ETL 的功能通过 Flink 的流式处理解决。此时就不存在调度和血缘管理的问题了,通过实时不断的增量更新,最终输出到业务的 DB 中。

虽然延时降低了,但此时我们会面临另外一些问题:
历史数据丢失,因为 Kafka 只是临时的存储介质,数据会有一个超时的时间 (比如只保存 7 天的数据),这会导致我们的历史数据丢失。
成本相对较高,实时计算的成本要大于离线计算。

Lambda 架构

基于Flink+Hive+Kafka的流批一体数仓实践--01架构及思想_第3张图片

所以此时很多人就会选择一套实时一套离线的做法,互不干扰,根据任务是否需要走实时的需求来对需求进行分离。

这套架构看似解决了所有问题,但实际带来的问题也是非常多。首先,Lambda 架构造成了离线和实时的割裂问题,它们解决的业务问题都是一样的,但是两套方案让同样的数据源产生了不同的计算结果。不同层级的表结构可能不一致,并且当数据产生不一致的问题时,还需要去进行比对排查。
随着这套 Lambda 架构越走越远,开发团队、表结构表依赖、计算模型等都可能会被割裂开,越到后面越会发现,成本越来越高,而统一的代价越来越大。
基于Flink+Hive+Kafka的流批一体数仓实践--01架构及思想_第4张图片

那么问题来了,实时数仓会耗费如此大的资源,且还不能保留历史数据,Lambda 架构存在如此多的问题,有什么方案可以解决呢?

数据湖

数据湖拥有不少的优点,原子性可以让我们做到准实时的批流一体,并且支持已有数据的修改操作。但是毕竟数据湖是新一代数仓存储架构,各方面都还不是很完美,目前已有的数据湖都强依赖于 Spark(当然 Flink 也正在拥抱数据湖),将数据迁移到数据湖需要团队对迁移成本和人员学习成本进行考量。

基于Flink+Hive+Kafka的流批一体数仓实践--01架构及思想_第5张图片

如果没有这么大的决心迁移数据湖,那有没有一个稍微缓和一些的方案加速已有的离线数仓呢?

Flink 在批流一体上的探索

统一元数据

基于Flink+Hive+Kafka的流批一体数仓实践--01架构及思想_第6张图片

Flink 一直持续致力于离线和实时的统一,首先是统一元数据。简单来说就是把 Kafka 表的元数据信息存储到 HiveMetaStore 中,做到离线和实时的表 Meta 的统一。(目前开源的实时计算并没有一个较为完善的持久化 MetaStore,Hive MetaStore 不仅能保存离线表,也可以承担实时计算的 MetaStore 能力)。

统一计算引擎

基于Flink+Hive+Kafka的流批一体数仓实践--01架构及思想_第7张图片

同样的元数据之后,实时和离线的表结构和层次可以设计成一样,接下来就是可以共用:
同一套 SQL,Flink 自身提供批流一体的 ANSI-SQL 语法,可以大大减小用户 SQL 开发者和运维者的负担,让用户专注于业务逻辑。
同一个引擎,Flink 的流和批复用一套优化和 Runtime 框架,现阶段的大数据引擎还远远达不到完全稳定的情况,所以仍然有很多时候需要我们去深入的分析和优化,一套引擎可以让开发者专注单个技术栈,避免需要接触多个技术栈,而只有技术广度,没有技术深度。

统一数据

基于Flink+Hive+Kafka的流批一体数仓实践--01架构及思想_第8张图片

分析了元数据和计算引擎的统一,更进一步,是否能统一实时和离线的数据,避免数据的不一致,避免数据的重复存储和重复计算。ETL 计算是否能统一呢?既然实时表设计上可以和离线表一模一样,是否可以干脆只有实时表的 ETL 计算,离线表从实时表里获取数据?
并且,通过实时链路可以加速离线链路的数据准备,批计算可以把调度换成流输入。

基于Flink+Hive+Kafka的流批一体数仓实践--01架构及思想_第9张图片

Flink Hive/File Streaming Sink 即为解决这个问题,实时 Kafka 表可以实时的同步到对于的离线表中:
离线表作为实时的历史数据,填补了实时数仓不存在历史数据的空缺。
数据批量准实时摄入为 Ad-hoc 查询离线表提供了准实时输入。

此时离线的批计算也可以交由实时调度,在实时任务处理中某个契机 (Partition Commit 见后续) 自行调度离线那块的任务进行数据同步操作。
此时实时和离线的表已经基本统一,那么问题来了,Kafka 中的表和 Hive 中的表能否就共用一张表呢?我的想法是之后可能会出现以下情况,在数仓中定义一张表,分别对应着 Kafka 和 Hive+HDFS 两种物理存储:

用户在进行 insert 操作时,就自然插入到了 Kafka 的实时 table 当中,同时生成另外一条链路,自动同步到 Hive Table 当中。这样这一张表就非常的完整,不仅满足实时的需求,而且拥有历史的数据。
一个 SQL 读取这样的一个 Hybrid Source ,根据你的查询语句后面的 where 条件,自动路由到 Hive 的历史数据,或者是 Kafka 的实时数据。根据一定的规则先读 Hive 历史数据,再读 Kafka 实时数据,当然这里有一个问题,它们之间通过什么标识来切换呢?一个想法是数据中或者 Kafka 的 Timestamp。

你可能感兴趣的:(flink)