基于 Flink+Iceberg 构建企业级实时数据湖

Apache Flink 是大数据领域很是流行的流批统一的计算引擎,数据湖是顺应云时代发展潮流的新型技术架构。那么当 Apache Flink 碰见数据湖时,会碰撞出什么样的火花呢?本次分享主要包括如下核心内容:git

  1. 数据湖的相关背景介绍;
  2. 经典业务场景介绍;
  3. 为何选择 Apache Iceberg;
  4. 如何经过 Flink+Iceberg 实现流式入湖
  5. 社区将来规划工做。

视频回顾:https://www.bilibili.com/vide...github

数据湖的相关背景介绍

数据湖是个什么概念呢?通常来讲咱们把一家企业产生的数据都维护在一个平台内,这个平台咱们就称之为“数据湖”。数据库

看下面这幅图,这个湖的数据来源多种多样,有的多是结构化数据,有的多是非结构数据,有的甚至是二进制数据。有一波人站在湖的入口,用设备在检测水质,这对应着数据湖上的流处理做业;有一批抽水机从湖里面抽水,这对应着数据湖的批处理做业;还有一批人在船头钓鱼或者在岸上捕鱼,这对应着数据科学家从数据湖中经过机器学习的手段来提取数据价值。apache

1.jpg

  1. 咱们总结起来,其实数据湖主要有 4 个方面的特色。
  2. 第一个特色是存储原始数据,这些原始数据来源很是丰富;
  3. 第二个特色是支持多种计算模型;
  4. 第三个特色是有完善的数据管理能力,要能作到多种数据源接入,实现不一样数据之间的链接,支持 schema 管理和权限管理等;
  5. 第四个特色是灵活的底层存储,通常用 ds三、oss、hdfs 这种廉价的分布式文件系统,采用特定的文件格式和缓存,知足对应场景的数据分析需求。

2.jpg

那么开源数据湖架构通常是啥样的呢?这里我画了一个架构图,主要分为四层:缓存

  1. 最底下是分布式文件系统,云上用户 S3 和 oss 这种对象存储会用的更多一些,毕竟价格便宜不少;非云上用户通常采用本身维护的 HDFS。
  2. 第二层是数据加速层。数据湖架构是一个存储计算完全分离的架构,若是全部的数据访问都远程读取文件系统上的数据,那么性能和成本开销都很大。若是能把常常访问到的一些热点数据缓存在计算节点本地,这就很是天然的实现了冷热分离,一方面能收获到不错的本地读取性能,另外一方面还节省了远程访问的带宽。这一层里面,咱们通常会选择开源的 alluxio,或者选择阿里云上的 Jindofs。
  3. 第三层就是 Table format 层,主要是把一批数据文件封装成一个有业务意义的 table,提供 ACID、snapshot、schema、partition 等表级别的语义。通常对应这开源的 Delta、Iceberg、Hudi 等项目。对一些用户来讲,他们认为Delta、Iceberg、Hudi 这些就是数据湖,其实这几个项目只是数据湖这个架构里面的一环,只是由于它们离用户最近,屏蔽了底层的不少细节,因此才会形成这样的理解。
  4. 最上层就是不一样计算场景的计算引擎了。开源的通常有 Spark、Flink、Hive、Presto、Hive MR 等,这一批计算引擎是能够同时访问同一张数据湖的表的。

3.jpg

经典业务场景介绍

那么,Flink 和数据湖结合能够有哪些经典的应用场景呢?这里咱们探讨业务场景时默认选型了 Apache Iceberg 来做为咱们的数据湖选型,后面一节会详细阐述选型背后的理由。架构

4.jpg

首先,Flink+Iceberg 最经典的一个场景就是构建实时的 Data Pipeline。业务端产生的大量日志数据,被导入到 Kafka 这样的消息队列。运用 Flink 流计算引擎执行 ETL后,导入到 Apache Iceberg 原始表中。有一些业务场景须要直接跑分析做业来分析原始表的数据,而另一些业务须要对数据作进一步的提纯。那么咱们能够再新起一个 Flink 做业从 Apache Iceberg 表中消费增量数据,通过处理以后写入到提纯以后的 Iceberg 表中。此时,可能还有业务须要对数据作进一步的聚合,那么咱们继续在iceberg 表上启动增量 Flink 做业,将聚合以后的数据结果写入到聚合表中。并发

有人会想,这个场景好像经过 Flink+Hive 也能实现。 Flink+Hive 的确能够实现,但写入到 Hive 的数据更多地是为了实现数仓的数据分析,而不是为了作增量拉取。通常来讲,Hive 的增量写入以 partition 为单位,时间是 15min 以上,Flink 长期高频率地写入会形成 partition 膨胀。而 Iceberg 允许实现 1 分钟甚至 30秒的增量写入,这样就能够大大提升了端到端数据的实时性,上层的分析做业能够看到更新的数据,下游的增量做业能够读取到更新的数据。机器学习

5.jpg

第二个经典的场景,就是能够用 Flink+Iceberg 来分析来自 MySQL 等关系型数据库的 binlog 等。一方面,Apache Flink 已经原生地支持 CDC 数据解析,一条 binlog 数据经过 ververica flink-cdc-connector 拉取以后,自动转换成 Flink Runtime 能识别的 INSERT、DELETE、UPDATE_BEFORE、UPDATE_AFTER 四种消息,供用户作进一步的实时计算。分布式

另一方面,Apache Iceberg 已经较为完善地实现了 equality delete 功能,也就是用户定义好待删除的 Record,直接写到 Apache Iceberg 表内就能够删除对应的行,自己就是为了实现数据湖的流式删除。在 Iceberg 将来的版本中,用户将不须要设计任何额外的业务字段,不用写几行代码就能够完成 binlog 流式入湖到 Apache Iceberg(社区的这个 Pull Request 已经提供了一个 flink 写入 CDC 数据的原型)。ide

此外,CDC 数据成功入湖 Iceberg 以后,咱们还会打一般见的计算引擎,例如 Presto、Spark、Hive 等,他们均可以实时地读取到 Iceberg 表中的最新数据。

6.jpg

第三个经典场景是近实时场景的流批统一。在经常使用的 lambda 架构中,咱们有一条实时链路和一条离线链路。实时链路通常由 Flink、Kafka、HBase 这些组件构建而成,而离线链路通常会用到 Parquet、Spark 等组件构建。这里面涉及到计算组件和存储组件都很是多,系统维护成本和业务开发成本都很是高。有不少场景,他们的实时性要求并无那么苛刻,例如能够放松到分钟级别,这种场景咱们称之为近实时场景。那么,咱们是否是能够经过 Flink + Iceberg 来优化咱们经常使用的 lambda 架构呢?

7.jpg

咱们能够用 Flink+Iceberg 把整个架构优化成上图所示。实时的数据经过 Flink 写入到 Iceberg 表中,近实时链路依然能够经过flink计算增量数据,离线链路也能够经过 flink 批计算读取某个快照作全局分析,获得对应的分析结果,供不一样场景下的用户读取和分析。通过这种改进以后,咱们把计算引擎统一成了 Flink,把存储组件统一成了 Iceberg,整个系统的维护开发成本大大下降。

8.jpg

第四个场景,是采用 Iceberg 全量数据和 Kafka 的增量数据来 Bootstrap 新的 Flink 做业。咱们现有的流做业在线上跑着,忽然有一天某个业务方跑过来讲,他们遇到一个新的计算场景,须要设计一个新的 Flink 做业,跑一遍去年一年的历史数据,跑完以后再对接到正在产生的 Kafka 增量数据。那么这时候应该怎么办呢?

咱们依然能够采用常见的 lambda 架构,离线链路经过 kafka->flink->iceberg 同步写入到数据湖,因为 Kafka 成本较高,保留最近 7 天数据便可,Iceberg 存储成本较低,能够存储全量的历史数据(按照 checkpoint 拆分红多个数据区间)。启动新 Flink 做业的时候,只须要去拉 Iceberg 的数据,跑完以后平滑地对接到 kafka 数据便可。

9.jpg

第五个场景和第四个场景有点相似。一样是在 lambda 架构下,实时链路因为事件丢失或者到达顺序的问题,可能致使流计算端结果不必定彻底准确,这时候通常都须要全量的历史数据来订正实时计算的结果。而咱们的 Iceberg 能够很好地充当这个角色,由于它能够高性价比地管理好历史数据。

为何选择 Apache Iceberg

回到上一节遗留的一个问题,为何当时 Flink 在众多开源数据湖项目中会选择 Apache Iceberg 呢?

10.jpg

咱们当时详细地调研了 Delta、Hudi、Iceberg 三个开源项目,并写了一篇调研报告。咱们发现 Delta 和 Hudi 跟 Spark 的代码路径绑定太深,尤为是写入路径。毕竟当时这两个项目设计之初,都多多少少把 Spark 做为的他们默认的计算引擎了。而Apache Iceberg 的方向很是坚决,宗旨就是要作一个通用化设计的 Table Format。所以,它完美地解耦了计算引擎和底下的存储系统,便于接入多样化计算引擎和文件格式,能够说正确地完成了数据湖架构中的 Table Format 这一层的实现。咱们认为它也更容易成为 Table Format 层的开源事实标准。

另一方面,Apache Iceberg 正在朝着流批一体的数据湖存储层发展,manifest 和snapshot 的设计,有效地隔离不一样 transaction 的变动,很是方便批处理和增量计算。而咱们知道 Apache Flink 已是一个流批一体的计算引擎,能够说这两者的长远规划完美匹配,将来两者将协力打造流批一体的数据湖架构。

最后,咱们还发现 Apache Iceberg 这个项目背后的社区资源很是丰富。在国外, Netflix、Apple、Linkedin、Adobe 等公司都有 PB 级别的生产数据运行在 Apache Iceberg 上;在国内,腾讯这样的巨头也有很是庞大的数据跑在 Apache Iceberg 之上,他们最大的一个业务天天有几十T的增量数据写入到 Apache Iceberg。社区成员一样很是资深和多样化,拥有来自其余项目的 7 位 Apache PMC,1 为 VP。体如今代码和设计的 review 上,就变得很是苛刻,一个稍微大一点的 PR 涉及 100+ 的comment 很常见。在我我的看来,这些都使得 Apache Iceberg 的设计+代码质量比较高。

正式基于以上考虑,Apache Flink 最终选择了 Apache Iceberg 做为第一个数据湖接入项目。

如何经过 Flink+Iceberg 实现流式入湖

目前,咱们已经在 Apache Iceberg 0.10.0 版本上实现 Flink 流批入湖功能,同时还支持 Flink 批做业查询 Iceberg 数据湖的数据。具体关于 Flink 如何读写 Apache Iceberg 表,能够参考 Apache Iceberg 社区的使用文档,这里再也不赘述。

https://github.com/apache/ice...

下面来简要阐述下 Flink iceberg sink 的设计原理:因为 Iceberg 采用乐观锁的方式来实现 Transaction 的提交,也就是说两我的同时提交更改事务到 Iceberg 时,后开始的一方会不断重试,等先开始的一方顺利提交以后再从新读取 metadata 信息提交 transaction。考虑到这一点,采用多个并发算子去提交 transaction 是不合适的,容易形成大量事务冲突,致使重试。

因此,咱们把 Flink 写入流程拆成了两个算子,一个叫作 IcebergStreamWriter,主要用来写入记录到对应的 avro、parquet、orc 文件,生成一个对应的 Iceberg DataFile,并发送给下游算子;另一个叫作 IcebergFilesCommitter,主要用来在 checkpoint 到来时把全部的 DataFile 文件收集起来,并提交 Transaction 到 Apache iceberg,完成本次 checkpoint 的数据写入。

11.jpg

理解了 Flink Sink 算子的设计后,下一个比较重要的问题就是:如何正确地设计两个算子的 state ?

首先,IcebergStreamWriter 的设计比较简单,主要任务是把记录转换成 DataFile,并无复杂的 State 须要设计。IcebergFilesCommitter 相对复杂一点,它为每一个checkpointId 维护了一个 DataFile 文件列表,即 map<Long, List<DataFile>>,这样即便中间有某个 checkpoint的transaction 提交失败了,它的 DataFile 文件仍然维护在 State 中,依然能够经过后续的 checkpoint 来提交数据到 Iceberg 表中。

社区将来规划工做等

Apache Iceberg 0.10.0 版本的发布,已经拉开集成 Flink 和 Iceberg 的序幕。在将来的 Apache Iceberg 0.11.0 和 0.12.0 版本中,咱们规划了更多高级功能及特性。

对于 Apache 0.11.0 版原本说,主要解决两个问题:

第一个事情是小文件合并的问题,固然 Apache Iceberg 0.10.0 版本已经支持了Flink 批做业定时去合并小文件,这个功能还相对较为初级。在 0.11.0 版本中,咱们将设计自动合并小文件功能,简单来讲就是在 Flink checkpoint 到达,触发 Apache Iceberg transaction 提交后,有一个专门的算子,专门负责处理小文件的合并工做。

第二个事情是 Flink streaming reader 的开发,目前咱们已经在私有仓库作了一些 PoC 工做,在将来的时间内咱们将贡献到 Apache Iceberg 社区。

对于 0.12.0 版原本说,主要解决 row-level delete 的问题。如前面提到,咱们已经在 PR 1663 中实现 Flink UPSERT 更新数据湖的全链路打通。后续在社区达成一致以后,将逐步推进该功能到社区版本。到时候用户将能经过 Flink 完成 CDC 数据的实时写入和分析,也能够方便地把 Flink 的聚合结果 upsert 到 Apache Iceberg 内。

做者介绍:

胡争(子毅),阿里巴巴技术专家,目前主要负责 Flink 数据湖方案的设计和开发工做,Apache Iceberg 及 Apache Flink 项目的长期活跃贡献者,《HBase 原理与实践》做者。