前言
本篇为大家带来Hudi的数据文件布局的一些个人理解。
本篇大量引用了
探索Apache Hudi核心概念 (1) - File Layouts一文。该文章对Hudi File layout的讲解非常详细。因此结合该文章,增加了本人的理解部分。如有不妥,请联系本人删除。
Hudi官网https://hudi.apache.org/docs/file_layouts/对Hudi文件布局的描述如下:
- Hudi表的所有内容(数据文件和元数据)在分布式文件系统下一个指定的目录中保存(称之为bash path)。
- Hudi表中的数据按照分区来存储(体现为以分区字段值命名的目录)。
- 在每个分区中数据文件按照file group来组织。属于同一个file group的数据文件具有相同的file ID。
- 每个file group包含多个file slice。
- 每个file slice包含一个base file和一系列log file(仅MOR表有log file)。Base file的存储格式由
hoodie.table.base.file.format
确定,由commit或compaction操作生成。Log file是对应的base file的增量数据,由deltacommit操作生成。
基本原则
“Hudi在文件操作上有一个重要“原则”:Hudi always creates immutable files on disk。即:文件一旦创建,永远不会再更新,任何添加、修改或删除操作只会在现有文件数据的基础上合并输入数据一起写入到下一个新文件中。”
Hudi的数据文件位于表base path中。如果有分区,数据文件位于base path的分区目录中。在同一个分区目录中,Hudi的数据文件没有层级划分。仅在逻辑上分为file slice和file group。
Hudi上存储中所有的文件都是一次性写入的。对于Base file(列存储),任何修改会创建出新的file slice,和原来的file slice的file id相同,属于同一个file group。但是它比原来的file slice时间戳更大,相当于“替换”了原来的file slice内容。保留原file slice的原因是可以通过time travel query等回溯历史数据。
Base file
“Base File是存储Hudi数据集的主体文件,以Parquet等列式格式存储,所以我们在Hudi中看到的Parquet文件基本都是Base File。实际上,Base File的命名是为了呼应Log File,在没有Log File的COW表里,Base File就是基层的数据存储文件,没必要强调它的“Base”身份,直接叫Parquet文件就可以。Base File遵循一致的命名规范,格式为:
<fileId>_<writeToken>_<instantTime>.parquet
fileId部分是一个uuid,我们会在多个文件中看到相同的fileId,这些fileId相同的文件就组成了一个File Group。instantTime是写入这个文件对应的instant的时间,也是该文件的一个“版本”标注,因为一个Base File历经多轮增删改操作后就会产生多个版本,Hudi就使用instantTime对它们进行标识。不管是MOR表还是COW表,都有Base File,只是在COW表里只有Base File,在MOR表里除了Base File还有Log File。”
Log file
“Log File是在MOR表中用于存储变化数据的文件,也常被称作Delta Log,Log File不会独立存在,一定会从属于某个Parquet格式的Base File,一个Base File和它从属的若干Log File所构成的就是一个File Slice。Log File也遵循一致的命名规范,格式为:
.<fileId>_<baseCommitTime>.log.<fileVersion>_<writeToken>
不同于Base File,Log File文件名中时间戳部分并不是Log File自己对应的instanceTime,而是它所从属的Base File的instanceTime,即baseCommitTime。如此一来,就没有办法通过时间戳来区分Log File提交的先后顺序了,所以Hudi在Log File文件名中加入了fileVersion,它是一个从1开始单调递增的序列号,用于标识Log File产生的顺序。”
Log file可以理解为base file的增量部分。在base file更新之前起到了数据缓存的作用。
File Slice
“在MOR表里,由一个Base File和若干从属于它的Log File组成的文件集合被称为一个File Slice。应该说File Slice是针对MOR表的特定概念,对于COW表来说,由于它不生成Log File,所以File Silce只包含Base File,或者说每一个Base File就是一个独立的File Silce。总之,对于COW表来说没有必要区分File Silce,也不没必要强调Base File的“Base”身份,只是为了概念对齐,大家会统一约定Hudi文件的三层逻辑布局为:File Group -> File Slice -> Base / Log Files。”
File slice对应了一批数据的某一个版本。file id相同的多个file slice分别对应同一批数据的不同版本。使用时间戳来区分数据的新旧。不同file id的file slice中不会有相同数据的多个版本。
File Group
“在前面介绍Base File时,我们已经提到了File Group,简单说,就是fileId相同的文件属于同一个File Group。同一File Group下往往有多个不同版本(instantTime)的Base File(针对COW表)或Base File + Log File的组合(针对MOR表),当File Group内最新的Base File迭代到足够大( >100MB)时,Hudi就不会在当前File Group上继续追加数据了,而是去创建新的File Group。”
同一个File Group中保存的是同一批数据的不同版本。在File Group中的旧数据文件(时间戳不为最新的base file)保存了这批数据的历史版本。
不同的File Group保存了不同的数据。因此查询最新数据的时候,同一个File Group中的文件只需要考虑最新版本的file slice。将不同file group的查询结果合并返回。
Hudi有文件大小控制功能。会尽力保持base file大小在配置的范围内。因此如果file group过小,新数据会优先追加到较小的file group中,创建新file group(数据切分)的逻辑是单个file group的数据量超过了配置上限。
每个file group中的数据分布可以通过clustering表服务来优化。将数据按照经常作为查询条件的字段,依照指定顺序排序存放。
Hudi表目录示意
MOR表:
-rw-r--r-- 3 hdfs hdfs 4283 2024-07-09 13:46 /hudi_student/.ba74ba57-d45c-43c7-9ddb-7c8afb3bab8f_20240709133903537.log.1_0-1-0
-rw-r--r-- 3 hdfs hdfs 4871 2024-07-10 08:42 /hudi_student/.ba74ba57-d45c-43c7-9ddb-7c8afb3bab8f_20240709134613722.log.1_0-1-0
-rw-r--r-- 3 hdfs hdfs 4074 2024-07-10 08:44 /hudi_student/.ba74ba57-d45c-43c7-9ddb-7c8afb3bab8f_20240710084244018.log.1_0-1-0
-rw-r--r-- 3 hdfs hdfs 815 2024-07-10 14:20 /hudi_student/.ba74ba57-d45c-43c7-9ddb-7c8afb3bab8f_20240710084455963.log.1_0-1-0
drwxr-xr-x - hdfs hdfs 0 2024-07-10 14:20 /hudi_student/.hoodie
-rw-r--r-- 3 hdfs hdfs 96 2024-07-09 13:39 /hudi_student/.hoodie_partition_metadata
-rw-r--r-- 3 hdfs hdfs 434687 2024-07-09 17:14 /hudi_student/ba74ba57-d45c-43c7-9ddb-7c8afb3bab8f_0-1-0_20240709134613722.parquet
-rw-r--r-- 3 hdfs hdfs 434725 2024-07-10 08:42 /hudi_student/ba74ba57-d45c-43c7-9ddb-7c8afb3bab8f_0-1-0_20240710084244018.parquet
-rw-r--r-- 3 hdfs hdfs 434756 2024-07-10 08:44 /hudi_student/ba74ba57-d45c-43c7-9ddb-7c8afb3bab8f_0-1-0_20240710084455963.parquet
COW表:
drwxr-xr-x - hdfs hdfs 0 2024-07-09 18:13 /hudi_student_cow/.hoodie
-rw-r--r-- 3 hdfs hdfs 96 2024-07-09 17:25 /hudi_student_cow/.hoodie_partition_metadata
-rw-r--r-- 3 hdfs hdfs 434759 2024-07-09 17:25 /hudi_student_cow/c0094994-a251-4933-8de6-6858da510517_0-1-0_20240709172551274.parquet
-rw-r--r-- 3 hdfs hdfs 434752 2024-07-09 17:55 /hudi_student_cow/c0094994-a251-4933-8de6-6858da510517_0-1-0_20240709175507082.parquet
-rw-r--r-- 3 hdfs hdfs 434758 2024-07-09 18:04 /hudi_student_cow/c0094994-a251-4933-8de6-6858da510517_0-1-0_20240709180410695.parquet
-rw-r--r-- 3 hdfs hdfs 434757 2024-07-09 18:13 /hudi_student_cow/c0094994-a251-4933-8de6-6858da510517_0-1-0_20240709181300182.parquet