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

本文介绍了Apache Flink与数据湖的结合,重点讨论了Apache Iceberg作为数据湖解决方案的原因及其应用场景。Apache Iceberg因其通用化设计、流批一体的能力以及强大的社区支持成为首选。文章详细阐述了Flink通过Iceberg实现流式入湖的原理,并展望了未来在小文件合并、流式读取等方面的发展规划。
摘要由CSDN通过智能技术生成

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

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

  1. 数据湖的相关背景介绍;
  2. 经典业务场景介绍。
  3. 为什么选择Apache Iceberg。
  4. 如何通过flink+iceberg实现流式入湖。
  5. 社区未来规划工作等。

数据湖的相关背景介绍

数据湖是个什么概念呢?一般来说我们把一家企业产生的数据都维护在一个平台内,这个平台我们就称之为“数据湖”。看下面这幅图,这个湖的数据来源多种多样,有的可能是结构化数据,有的可能是非结构数据,有的甚至是二进制数据。有一波人站在湖的入口,用设备在检测水质,这对应着数据湖上的流处理作业;有一批抽水机从湖里面抽水,这对应着数据湖的批处理作业;还有一批人在船头钓鱼或者在岸上捕鱼,这对应着数据科学家从数据湖中通过机器学习的手段来提取数据价值。

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

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

  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等,这一批计算引擎是可以同时访问同一张数据湖的表的。

经典业务场景介绍

那么,Flink和数据湖结合可以有哪些经典的应用场景呢?(这里我们探讨业务场景时默认选型了Apache Iceberg来作为我们的数据湖选型,后面一节会详细阐述选型背后的理由)

首先,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秒的增量写入,这样就可以大大提高了端到端数据的实时性,上层的分析作业可以看到更新的数据,下游的增量作业可以读取到更新的数据。

第二个经典的场景,就是可以用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数据的原型)。此外,CDC数据成功入湖Iceberg之后,我们还会打通常见的计算引擎,例如presto、spark、hive等,他们都可以实时地读取到iceberg表中的最新数据。

第三个经典场景是近实时场景的流批统一。在常用的lambda架构中,我们有一条实时链路和一条离线链路。实时链路一般由flink、kafka、hbase这些组件构建而成,而离线链路一般会用到parquet、spark等组件构建。这里面涉及到计算组件和存储组件都非常多,系统维护成本和业务开发成本都非常高。有很多场景,他们的实时性要求并没有那么苛刻,例如可以放松到分钟级别,这种场景我们称之为近实时场景。那么,我们是不是可以通过flink + iceberg来优化我们常用的lambda架构呢?

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

第四个场景,是采用Iceberg全量数据和Kafka的增量数据来Bootstrap新的Flink作业。我们现有的流作业在线上跑着,突然有一天某个业务方跑过来说,他们遇到一个新的计算场景,需要设计一个新的flink作业,跑一遍去年一年的历史数据,跑完之后再对接到正在产生的Kafka增量数据。那么这时候应该怎么办呢?我们依然可以采用常见的lambda架构,离线链路通过kafka->flink->iceberg同步写入到数据湖,由于kafka成本较高,保留最近7天数据即可,Iceberg存储成本较低,可以存储全量的历史数据(按照checkpoint拆分成多个数据区间)。启动新Flink作业的时候,只需要去拉Iceberg的数据,跑完之后平滑地对接到kafka数据即可。

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

为什么选择Apache Iceberg

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

我们当时详细地调研了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社区的使用文档,这里不再赘述。

下面来简要阐述下flink iceberg sink的设计原理: 由于Iceberg采用乐观锁的方式来实现Transaction的提交,也就是说两个人同时提交更改事务到Iceberg时,后开始的一方会不断重试,等先开始的一方顺利提交之后再重新读取metadata信息提交transaction。考虑到这一点,采用多个并发算子去提交transaction是不合适的,容易造成大量事务冲突,导致重试。所以,我们把Flink写入流程拆成了两个算子,一个叫做IcebergStreamWriter,主要用来写入记录到对应的avro、parquet、orc文件,生成一个对应的Iceberg DataFile,并发送给下游算子;另外一个叫做IcebergFilesCommitter,主要用来在checkpoint到来时把所有的DataFile文件收集起来,并提交Transaction到Apache iceberg,完成本次checkpoint的数据写入。

理解了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内。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值