一.简介
Apache Paimon 原名 Flink Table Store,2022年1月在 Apache Flink 社区从零开始研发,Flink 社区希望能够将 Flink 的 Streaming 实时计算能力和 Lakehouse 新架构优势进一步结合,促进数据在数据湖上真正实时流动起来,并为用户提供实时离线一体化的开发体验。
二.基本概念
1、快照 (Snapshot)
快照捕获表在某个时间点的状态。用户可以通过最新的快照访问表的最新数据,并利用时间线回溯通过较早的快照访问表的先前状态。在 Flink Checkpoint 时 Paimon 会产生 1~2 个 Snapshot,这取决于 Paimon 在这个过程中是否有进行过 Compaction,但至少会产生一个 Snapshot 来作为新的数据版本,通过定义Checkpoint Interval 来控制 Snapshot 的生成。
2、分区 (partition)
Paimon 采用与 Apache Hive 相同的分区概念来分离数据。
分区是一种可选方法,可根据日期、城市和部门等特定列的值将表划分为相关部分。每个表可以有一个或多个分区键来标识特定分区。
通过分区,用户可以高效地操作表中的一片记录。
3、桶 (bucket)
未分区表或分区表中的分区被细分为存储桶,以便为可用于更有效查询的数据提供额外的结构。桶的范围由记录中的一列或多列的哈希值确定。用户可以通过提供bucket-key选项来指定分桶列。如果未指定bucket-key选项,则主键(如果已定义)或完整记录将用作存储桶键。桶是读写的最小存储单元,因此桶的数量限制了最大处理并行度。不过这个数字不应该太大,因为它会导致大量小文件和低读取性能。一般来说,建议每个桶的数据大小为1GB左右
4. 清单文件 (Manifest Files)
所有快照文件都存储在快照目录中。快照文件是一个JSON 文件,包含有关此快照的信息,包括:正在使用的Schema文件,包含此快照的所有更改的清单列表(manifest list)
Manifest Files:所有清单列表(manifest list)和清单文件(manifest file)都存储在清单,清单文件(manifest file)是包含有关 LSM 数据文件和更改日志文件的文件信息。例如对应快照中创建了哪个LSM数据文件、删除了哪个文件。
5.数据文件 (Data Files)
数据文件按分区和存储桶分组。每个存储桶目录都包含一个 LSM 树及其变更日志文件。目前,Paimon 支持使用 orc(默认)、parquet 和 avro 作为数据文件格式。
6. 消费组 Consumer
类似消息队列kafka中的消费组的概念,主要用户记录流式处理中消费进度的记录,kafka的消费组记录消费offet的记录,paimon的消费组记录消费snapshot的进度。
三.Paimon 表类型
1、主键表
这是一个基本的 cahngelog 表,默认表类型,可进行 Upsert 操作。核心点是有主键,带更新的。主键由一组包含每个记录的唯一值的列组成,Paimon 通过对每个存储桶内的主键进行排序来强制数据排序,允许用户通过对主键应用过滤条件来实现高性能查询。
由于该表用于存储changelogs 流,因此当具有相同主键的两个或多个记录到达时, Paimon 提供各种 Merge 引擎。
2、仅追加表
仅追加表是没有主键的表。该表只允许插入操作。不支持删除或更新操作。此类表适合不需要更新的用例,例如日志数据同步。
3、外部日志系统
除了上述的表类型之外,Paimon 还支持外部日志系统。当使用外部日志系统并将数据写入数据湖时,数据也会写入到Kafka等系统中。如果使用外部日志系统,表文件和日志系统会记录所有写入,但流式查询产生的更改将来自日志系统而不是表文件。
四.Sequence and Rowkind
在创建表时,可以指定“顺序”。通过指定字段来确定更新的顺序,或者您可以指定‘rowkind ’。字段'来确定更改日志类型的记录。
Sequence Field
默认情况下,主键表根据输入顺序确定合并顺序(最后一个输入记录将是最后一个合并)。然而,在分布式计算中,会出现一些导致数据混乱的情况。此时,您可以使用时间字段作为序列
Flink
CREATE TABLE my_table (
pk BIGINT PRIMARY KEY NOT ENFORCED,
v1 DOUBLE,
v2 BIGINT,
update_time TIMESTAMP
) WITH (
'sequence.field' = 'update_time'
);
序列最大的记录。字段值将是最后一个要合并的,如果值相同,将使用输入顺序来确定哪个是最后一个。序列。Field支持所有数据类型的字段。
您可以为sequence定义多个字段。字段,例如‘update_time,flag’,多个字段将按顺序进行比较。
用户定义的序列字段与first_row和first_value等特性冲突,这可能会导致意想不到的结果。
Row Kind Field
默认情况下,主键表根据输入行确定行类型。你也可以定义行类型。字段'使用字段提取行类型。
有效的行类型字符串应该是‘+ I’,‘- U’,“U +”或“- d”。
五.消费组机制
在流读中经常碰到非常头疼的东西就是 FileNotFoundException,这个机制是什么样的呢?在数据产出过程当中,需要不断地产生 Snapshot。太多的 Snapshot 会导致大量的文件、导致数据存储非常地冗余,所以需要有 Snapshot 的清理机制。但是另外流读的作业可不知道这些,万一正在流读的 Snapshot 被 Snapshot Expiration 给删了,那不就会出现 FileNotFoundException,怎么办?而且更为严重的是,流读作业可能会 Failover,万一它挂了 2 个小时,重新恢复后,它正在流读的 Snapshot 已经被删除了,再也恢复不了。
所以 Paimon 在这里提出了 Consumer 机制。Consumer 机制就是在 Paimon 里用了这个机制之后,会在文件系统中记一个进度,当我再读这个 Snapshot,Expiration 就不会删这个 Snapshot,它能保证这个流读的安全,也能做到像类似 Kafka Group Id 流读进度的保存。重启一个作业无状态恢复还是这个进度。所以 Consumer 机制可以说是流读的基本机制。
消费组存在的好处
1.当前一个作业停止时,新启动的作业可以继续使用前一个进度,而无需从状态恢复。新的读取将 从消费者文件中找到的下一个快照id开始读取。
2.在确定快照是否过期时,Paimon查看文件系统中表的所有消费者,如果仍然有消费者依赖于该 快照,则该快照将不会在到期时被删除。
3.当没有水印定义时,Paimon表会将快照中的水印传递给下游的Paimon表,这意味着您可以跟踪 整个管道的水印进度。
注意:消费者将阻止快照过期,可以指定consumer.expiration-time来管理消费者的生命周期。可以使用给定的消费者ID和下一个快照ID重置消费者。