Iceberg作为凌驾于HDFS和S3等存储系统之上的数据组织框架,提供了数据写入、读取、文件管理和元数据管理等基本功能,虽然Iceberg提供了丰富的API接口,但是面向API开发需要使用方比较了解其原理和实现细节,还是显得门槛过高。此外,在面向实时数据读写场景,需要有一个桥接框架来自动完成数据的读写,于是Iceberg和Flink成为天作之合,本文就来研究下Iceberg是如何跟Flink对接的。
https://zhuanlan.zhihu.com/p/462501779
https://zhuanlan.zhihu.com/p/462501410
https://zhuanlan.zhihu.com/p/462501080
https://zhuanlan.zhihu.com/p/462500344
https://zhuanlan.zhihu.com/p/462496725
https://zhuanlan.zhihu.com/p/462498014
https://zhuanlan.zhihu.com/p/462498474
Flink写入Iceberg总体流程介绍
Flink典型的数据处理链路是Source->Transform->Sink,对Iceberg来讲,也遵从这一模式,比如下图:
Custom Souce是自定义的数据源类型的Source,用于向下游发送数据,比如下面的数据来源于静态List集合:
DataStream dataStream = env.fromCollection(list)
IcebergStreamWriter起着数据变换作用,跟Source 组成链式Operator,IcebergFilesCommiter作为Sink,将数据提交到本地文件test表。
Source端发送数据到IcebergStreamWriter,IcebergFilesCommiter将从IcebergStreamWriter获取的数据提交到元数据管理系统,比如Hive Metastore或者文件系统。当成功提交元数据之后,写入的数据才对外部可见。在这一个过程中,IcebergStreamWriter除了相当于上述链路模式中的Transform角色之外,还有一个重要原因:实现事务提交隔离。IcebergStreamWriter将数据暂时写入到一个缓冲文件,该文件暂时对外部是不可见的,然后IcebergFilesCommiter再将IcebergStreamWriter写入的文件的元信息,比如路径、文件大小,记录行数等写入到ManifestFile中,最后将ManifestFile文件元信息再写入到ManifestList(ManifestList即快照信息),ManifestList又被写入以版本号区分的metadata文件中(v%版本号%.metadata.json),下图展示了一个完整的数据包括元数据组织示例:
下面展开来讲下实现上述目标的细节内容:
首先Source端DataStream数据流经过IcebergStreamWriter变换,生成新的DataStream: SingleOutputStreamOperator ,输出类型是WriteResult:
//DataStream input
//IcebergStreamWriter streamWriter
SingleOutputStreamOperator writerStream = input
.transform(operatorName(ICEBERG_STREAM_WRITER_NAME), TypeInformation.of(WriteResult.class), streamWriter)
.setParallelism(parallelism);
其中WriteResult的定义如下:
public class WriteResult implements Serializable {
private DataFile[] dataFiles;
private DeleteFile[] deleteFiles;
private CharSequence[] referencedDataFiles;
…
}
从类定义可知,IcebergStreamWriter的输