文件大小调整
解决小文件问题是确保数据湖良好体验的基础。如果文件大小不合适,查询和数据管道都会变慢。你可能遇到的小文件问题包括以下几方面:
- 查询变慢:为了获取查询所需的数据,你不得不扫描大量小文件。这是一种非常低效的数据访问与利用方式。此外,像 S3 这样的云存储会对存储桶中每个前缀每秒可处理的请求数量施加速率限制。文件数量越多(即无论文件大小如何,每个文件至少需要一个请求),触发速率限制的概率就越大,同时打开和关闭文件也会带来额外的固定开销。所有这些都会导致查询变慢。
- 管道变慢:过多的调度开销或内存需求可能会拖慢你的 Spark、Flink 或 Hive 作业;文件越多,创建的任务就越多。
- 存储效率低下:处理大量小文件时,存储资源的利用可能不够高效。例如,大量小文件的压缩率较低,会增加存储成本。如果你对数据建立索引,还需要额外的存储空间来保存列统计信息等元数据。处理少量数据时,存储方面可能不会受到明显影响;但当数据规模达到 PB 甚至 EB 级别时,就必须高效地管理存储资源。
避免产生小文件是 Hudi 架构中的一项关键设计决策。Hudi 经过专门设计,能够自动写出大小合适的文件。本页将介绍 Apache Hudi 如何克服令人头疼的小文件问题。Hudi 中有两种管理小文件的方式:
下面我们将分别介绍这两种方式的优势与权衡。
note
bulk_insert 写入操作在数据摄取期间不具备自动调整文件大小的能力
写入时自动调整文件大小
你可以在摄取过程中通过 Hudi 的自动文件大小调整能力来管理文件大小。Parquet 基础文件的默认目标文件大小为 120MB,可通过 hoodie.parquet.max.file.size 进行配置。自动调整文件大小可能会带来一些写入延迟,但它能确保在写入事务提交后查询始终高效。需要注意的是,如果你在写入时不管理文件大小,而是试图定期运行聚类来修复文件大小,那么在聚类完成之前,你的查询可能会很慢。此功能目前仅支持**追加(append)**场景;**可变(mutable)**场景目前尚不支持。详情请参阅聚类文档。
如果你需要控制文件大小,即增大目标文件大小或更改小文件的识别方式,请按照以下说明针对 Copy-On-Write 和 Merge-On-Read 表进行配置。
Copy-On-Write (COW) 与 Merge-On-Read (MOR) 表的文件大小调整
要调整 COW 表和 MOR 表的文件大小,可以设置小文件限制和 Parquet 文件最大大小。Hudi 会在写入时尝试向小文件中添加足够的记录,使其达到配置的最大限制。
- 例如,如果
hoodie.parquet.small.file.limit=104857600(100MB)且hoodie.parquet.max.file.size=125829120(120MB),Hudi 将选取所有小于 100MB 的文件,并尝试将其填充至 120MB。
在首次创建 Hudi 表时,设置准确的记录大小估算值至关重要,这样才能确保 Hudi 能够充分估算出首个摄取批次中一个 Parquet 文件需要打包多少条记录。此后,Hudi 会根据之前的提交,自动使用平均记录大小来进行后续写入。
关于 Merge-On-Read (MOR) 表文件大小调整的更多细节
与 COW 表相比,MOR 表旨在降低写放大,因此在向 MOR 表写入时,Hudi 在插入和更新插入(upsert)操作的自动文件大小调整过程中,会将 Parquet 基础文件的数量限制为一个,从而限制被重写的文件数量。该限制可通过 hoodie.merge.small.file.group.candidates.limit 进行配置。
对于支持追加(append)操作的存储系统,除了调整 MOR 表 Parquet 基础文件的大小外,你还可以通过 hoodie.logfile.max.size 调整日志文件的大小。
MergeOnRead 在不同的 INDEX 选择下工作方式不同,因此还需要设置以下几个配置:
- 索引设置 canIndexLogFiles = true:新数据的插入直接写入日志文件。此时,你可以配置最大日志大小以及一个系数,该系数表示数据从 avro 文件转换为 parquet 文件时的体积缩小比例。
- 索引设置 canIndexLogFiles = false:新数据的插入只写入 parquet 文件。此时,适用于上述 COPY_ON_WRITE 场景的相同配置同样生效。注意:无论哪种情况,只有当该特定文件切片不存在待处理(PENDING)的 compaction 或关联的日志文件时,小文件才会被自动调整大小。例如,对于情形 1:如果已存在一个日志文件,并且已调度 compaction C1 将该日志文件转换为 parquet,则不再有新的插入写入该日志文件。对于情形 2:如果已存在一个 parquet 文件,而一次更新操作创建了关联的增量日志文件,则不再有新的插入写入该 parquet 文件。只有在 compaction 执行完毕、且与基础 parquet 文件关联的日志文件已全部消除之后,新的插入才会被发送以自动调整该 parquet 文件的大小。
配置项
以下是 COW 表的关键配置。
基于 Spark 的配置:
配置名称默认值描述
hoodie.parquet.small.file.limit104857600 (可选)在插入和更新操作期间,我们会机会性地扩展现有的存储小文件,而不是写入新文件,以保持文件数量处于最优状态。该配置设置了文件大小阈值,存储上小于该大小的文件将被选为这样的「小文件」。默认将任何大小 <= 100MB 的文件视为小文件。另请注意,如果该值设置为 <= 0,则不会尝试查找小文件,而是直接写入新文件
Config Param: PARQUET_SMALL_FILE_LIMIT
hoodie.parquet.max.file.size125829120 (可选)Hudi 写入阶段生成的 parquet 文件的目标大小(字节)。对于 DFS,该值需要与底层文件系统的块大小保持一致,以获得最佳性能。
Config Param: PARQUET_MAX_FILE_SIZE
hoodie.copyonwrite.record.size.estimate1024 (可选)记录的平均大小。如果未显式指定,Hudi 将根据提交元数据动态计算记录大小的估计值。这对于计算插入并行度以及将插入数据装箱到小文件中至关重要。
Config Param: COPY_ON_WRITE_RECORD_SIZE_ESTIMATE
基于 Flink 的配置:
配置名称默认值描述
write.parquet.max.file.size120 (可选)Hudi 写入阶段生成的 parquet 文件的目标大小。对于 DFS,该值需要与底层文件系统的块大小保持一致,以获得最佳性能。
Config Param: WRITE_PARQUET_MAX_FILE_SIZE
以下是 MOR 表的关键配置:
基于 Spark 的配置:
配置名称默认值描述
hoodie.parquet.small.file.limit104857600 (可选)在插入和更新操作期间,我们会尝试就地扩展已有的小文件,而不是写入新文件,以使文件数量保持在合理水平。该配置用于设定文件大小阈值,存储上的文件小于该阈值时,会被视为候选的「小文件」。默认情况下,任何小于等于 100MB 的文件都会被当作小文件。另外请注意,如果该值设置为小于等于 0,则不会去查找小文件,而是直接写入新文件。
Config Param: PARQUET_SMALL_FILE_LIMIT
hoodie.parquet.max.file.size125829120 (可选)Hudi 写入阶段产出的 Parquet 文件的目标大小(字节)。对于分布式文件系统,为了获得最佳性能,该值需要与底层文件系统的块大小保持一致。
Config Param: PARQUET_MAX_FILE_SIZE
hoodie.merge.small.file.group.candidates.limit1 (可选)限制在更新操作中,考虑用于追加记录的、其基础文件满足小文件阈值的文件组数量。仅适用于 MOR 表。
Config Param: MERGE_SMALL_FILE_GROUP_CANDIDATES_LIMIT
hoodie.logfile.max.size1073741824 (可选)日志文件的最大大小(字节)。这是日志文件滚动到下一个版本之前所允许的最大大小。该日志滚动阈值仅对支持追加操作的存储系统生效。请注意,在 S3/GCS 等云存储上,该设置可能不会被遵守。
Config Param: LOGFILE_MAX_SIZE
hoodie.logfile.to.parquet.compression.ratio0.35 (可选)记录从日志文件迁移到 Parquet 文件时预期的额外压缩比。用于 merge_on_read 表,以将插入数据发送到日志文件,并控制压缩后 Parquet 文件的大小。
Config Param: LOGFILE_TO_PARQUET_COMPRESSION_RATIO_FRACTION
基于 Flink 的配置:
配置名称默认值描述
write.parquet.max.file.size120 (可选)Hudi 写入阶段产出的 Parquet 文件的目标大小。对于分布式文件系统,为了获得最佳性能,该值需要与底层文件系统的块大小保持一致。
Config Param: WRITE_PARQUET_MAX_FILE_SIZE
write.log.max.size1024 (可选)日志文件在滚动到下一个版本之前允许的最大大小(MB),默认为 1GB。
Config Param: WRITE_LOG_MAX_SIZE
借助聚簇实现自动调整大小
聚簇(Clustering)是一项服务,可以将小文件合并为更大的文件,同时(可选地)通过对数据排序或应用空间填充曲线(如 Z-order 或 Hilbert 曲线)来改变数据布局。我们不会在此详细介绍聚簇的所有细节,更多内容请参阅聚簇章节。
聚类是实现文件尺寸控制的一种方式,可以让查询更快。摄入数据时,你可能仍会得到大量小文件(取决于你的配置以及摄入的数据量,即输入批次的大小)。在这种情况下,你需要将所有小文件聚类为更大的文件,以提升查询性能。聚类可以通过不同方式执行。更多详情请参阅聚类文档。
聚类非常有用的一个场景是:用户的 Hudi 表中存在大量小文件。例如,如果你在使用不带任何排序模式的 BULK_INSERT,或者你想要不同的文件布局,你可以使用聚类服务在不摄入任何新数据的情况下修复所有文件的大小。
note
Hudi 中的聚类不是阻塞操作,只要聚类服务运行期间没有文件需要被更新,写入就可以并发继续进行。如果在聚类服务运行期间对正在聚类的数据进行了更新,写入将会失败。
note
Hudi 始终在存储上创建不可变的文件。为了实现自动尺寸调整或聚类,Hudi 会始终创建较小文件的较新版本,从而产生同一文件的两个版本。之后清理服务会介入,删除较旧版本的小文件并保留最新版本。
以下是关键的文件尺寸配置:
配置
Spark 相关配置:
| 配置名称 | 默认值 | 描述 |
|---|---|---|
| hoodie.clustering.plan.strategy.small.file.limit | 314572800(可选) | 小于此处指定字节大小的文件是聚类的候选文件 |
Config Param: PLAN_STRATEGY_SMALL_FILE_LIMIT |
||
Since Version: 0.7.0 |
||
| hoodie.clustering.plan.strategy.target.file.max.bytes | 1073741824(可选) | 每个分组可以产生 'N'(CLUSTERING_MAX_GROUP_SIZE/CLUSTERING_TARGET_FILE_SIZE)个输出文件组 |
Config Param: PLAN_STRATEGY_TARGET_FILE_MAX_BYTES |
||
Since Version: 0.7.0 |
Flink 相关配置:
| 配置名称 | 默认值 | 描述 |
|---|---|---|
| clustering.plan.strategy.small.file.limit | 600(可选) | 小于此处指定大小的文件是聚类的候选文件,默认 600 MB |
Config Param: CLUSTERING_PLAN_STRATEGY_SMALL_FILE_LIMIT |
||
| clustering.plan.strategy.target.file.max.bytes | 1073741824(可选) | 每个分组可以产生 'N'(CLUSTERING_MAX_GROUP_SIZE/CLUSTERING_TARGET_FILE_SIZE)个输出文件组,默认 1 GB |
Config Param: CLUSTERING_PLAN_STRATEGY_TARGET_FILE_MAX_BYTES |
视频
评论
登录后参与评论
KnowForge