背景
互联网技术高速发展的背景下,数据已经成为各大公司的最宝贵资源之一。大数据领域经过近十年的高速发展,无论是离线计算还是实时计算、不管是数据仓库还是数据中台都已深入各大公司的各个业务。在复杂业务的背景下,迫切需要一套高效的大数据架构。以数据仓库为例,经过了几次架构升级。其中,首先诞生的一个比较成熟的流批一体架构就是Lambda架构,然后就是升级版的 Kappa 架构。
对于传统的 Lambda 架构,流与批是两条割裂的链路,维护成本高且容易出现数据不一致的情况。新的 Kappa 架构使用 Kafka 作为存储,简化了架构,但是 Kafka 的数据承载能力有限且数据格式不利于计算引擎进行数据分析。
Lambda 架构至今也是很多公司使用的成熟架构,其中令我们非常头疼的一个痛点就是,即使我们选用了 Flink Hive 的近实时的架构支持了实时读写,也会面临着一些问题的困扰。这些问题就是随着Hive中的表和分区越来越多并且对分区的实时性要求越高的时候,就会产生非常多的元数据,这对 Hive 的 Metastore 以及存储 Hive 元数据的数据库的产生很大的压力。而且,元数据过多也会导致生成查询计划变慢,严重的会影响到线上业务的稳定性。
Kappa 架构中也有令我们很头疼的痛点。其中,Kafka 本身存储成本很高且数据的保留具有时效性。如果消费端出现故障导致数据积压,那么当数据到达过期时间后就会造成数据丢失且没有被消费。这种情况的后果可能是灾难性的。
基于以上痛点,我们有没有一种可用的方案,好用的架构来解决它们呢?
答案是肯定的,这就是本文要介绍的流批一体、仓湖融合的升级架构解决方案以及高效的数据入湖配套方案。
升级架构
升级之后的架构如下,我们引入了 Iceberg。
针对 Lambda 架构,将原先的 Hive 近实时业务数据迁移到 Iceberg 中,而 Iceberg 本身的设计就可以处理元数据量大的问题;针对 Kappa 架构,对于实时性要求不高的数据存入 Iceberg 中,同时可以缩短 Kafka 的数据存储时间以满足业务的分钟级实时性需求,而对于实时性要求比较高的业务数据,同样可以通过 Iceberg 备份 Kafka 中的数据,这样既满足实时要求比较高的场景也能保留历史数据,而历史数据可用于数据重放等场景的需求。
Iceberg何以解决这些问题
- Iceberg 架构解析 从存储角度上来看 Iceberg 分为三层。最底层是具体的数据文件,中间是每次 Transaction 提交时生成的 Manifest 文件,最上层是 Snapshot 文件。Snapshot 是指每个时间点看到的整个表的全局数据。写入过程如下:
第一次 Transaction 的时候向 Iceberg 中写入了阴影部分文件的数据,读取也是读取阴影部分的数据。
第二次 Transaction 写入数据之后,读到的是新的阴影部分的数据。
依此类推,最后一次 Transaction 写入数据之后,读取到的就是上图灰白色阴影中的数据。
- Iceberg 为何可以处理大量元数据? 总体来讲 Iceberg 分为两部分数据,第一部分是数据文件,例如下图中的 Parquet 文件,每个数据文件对应一个校验文件(.crc文件)。第二部分是表元数据文件(Metadata 文件),包含 Snapshot 文件(snap-.avro)、Manifest文件(.avro)、TableMetadata 文件(*.json)等。
Iceberg 之所以能处理能处理大量元数据,与其精巧的存储结构设计密切相关。如上图所示,Iceberg 是把 Data 和 Metadata 都维护在可扩展的分布式文件系统之中的,因此它不存在中心化元数据的问题。Hive则是把 Partition 之上的元数据维护在 Metastore 里,当 Partition 过多则会给 MYSQL 造成巨大压力,而 Partition 之内的元数据则是维护在文件内的。
- Iceberg 何以能做近实时入湖 我们以 Flink 写入 Iceberg 为例详细阐述为何 Iceberg 只能做近实时的入湖,如下图所示:
其中,IcebergStreamWriter 主要用来写入记录到对应的 Avro、Parquet 文件,生成一个对应的 Iceberg Datafile,并发送给下游算子。IcebergFilesCommitter 主要用来在 Checkpoint 到来时把所有的 DataFile 文件收集起来并提交 Transaction 到 Apache Iceberg,完成本次 Checkpoint 的数据写入。因此 Iceberg 只能做近实时的入湖:
- Iceberg 提交 Transaction 时是以文件粒度来提交的,这就无法以秒为单位提交 Transaction,否则会造成文件数量膨胀
- Flink 写入以 Checkpoint 为单位,物理数据写入 Iceberg 之后并不能直接查询,当触发了 Checkpoint 之后才会写 Metadata 文件,这时数据由不可见变为可见,Checkpoint 每次执行也会需要一定时间。
数据入湖
对于数据入湖用户可能最关心的就是数据一致性问题。数据同步链路我们可以采用 Flink,可以保证 Exactly once 的语义,当作业发生故障,能够做严格的恢复,保证数据的一致性。Iceberg 本身提供了严谨的 ACID 语义,保证了数据的流入和查询的隔离性,不会产生脏数据。本文将介绍一个比较常用的数据入湖的使用场景,MYSQL 分库分表的数据同步到 Iceberg 中的一张表中。本地实操可参考Flink CDC构建实时数据湖[1]。企业级实战请使用腾讯云流计算Oceanus[2]。
参考连接
[1] FlinkCDC构建实时数据湖: https://ververica.github.io/flink-cdc-connectors/release-2.2/content/quickstart/build-real-time-data-lake-tutorial.html [2] 腾讯云流计算Oceanus: https://cloud.tencent.com/document/product/849