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 可以很好地充当这个角色,因为它可以高性价比地管理好历史数据。