Hive 小文件合并参数详解

一、输入端参数(控制读取时如何合并小文件,减少 Mapper 数量)

这 4 个参数共同决定 Hive 读取数据时,如何将大量物理小文件"打包"成较少的逻辑分片(InputSplit),从而避免为每个小文件都启动一个 Mapper。

1. hive.input.format
sql 复制代码
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
  • 作用:启用 Hive 的组合输入格式。

  • 原理 :默认的 TextInputFormat 等会为每个文件生成至少一个分片。CombineHiveInputFormat 则可以将多个小文件合并到一个分片中,用一个 Mapper 处理多个文件。

  • 重要性这是下面三个参数生效的前提 。如果不启用它,mapred.min.split.size.per.nodeper.rack 将不起作用。

2. mapred.max.split.size
sql 复制代码
set mapred.max.split.size=256000000;  -- 256 MB
  • 作用:设定一个分片的最大大小。

  • 配合 CombineHiveInputFormat 的含义 :在把小文件打包时,一个组合分片的总大小不会超过这个值。它的作用是防止合并后的分片过大、降低并行度

  • 效果:比如大量小文件总共有 1 GB,如果不设上限,可能全部合进一个分片,丢失并行性。设 256 MB 后,会被拆成约 4 个分片。

3. mapred.min.split.size.per.node
sql 复制代码
set mapred.min.split.size.per.node=100000000;  -- 100 MB
  • 作用 :在同一个 DataNode 上合并小文件时,期望每个分片至少达到这个大小。

  • 原理CombineFileInputFormat 会优先合并位于同一节点上的小文件。当组合文件总大小未达到 100 MB 时,会继续把该节点上更多小文件加入;如果某节点上所有文件加起来仍不足 100 MB,则会把它们全放进一个分片,不再等待。

  • 效果:保证节点本地性(node-local)的前提下,尽可能让每个分片包含足够数据,减少 Mapper 数量。

4. mapred.min.split.size.per.rack
sql 复制代码
set mapred.min.split.size.per.rack=100000000;  -- 100 MB
  • 作用 :当同一个节点上的文件不够凑满 min.split.size.per.node 时,允许跨节点但在同一机架内继续合并,直到达到这个大小。

  • 原理 :如果某个 DataNode 上只有 20 MB 的小文件,系统会尝试拉取同机架内其他节点的小文件,合并成一个大分片。这样牺牲了节点本地性(变成了机架本地性),但避免了产生零碎 Mapper。

  • 取值 :通常和 per.node 设成一样或稍大一点,此处设为相同的 100 MB,表示不论节点还是机架级别,都希望至少 100 MB 一个分片。

输入端总结

启用 CombineHiveInputFormat 后,系统会按"节点内达到 100 MB → 不足则机架内达到 100 MB → 但每个分片不超过 256 MB"的规则,把大量小文件合并处理,大幅减少 Mapper 数量


二、输出端参数(控制写入后如何合并小文件,优化最终表文件)

这 4 个参数负责在 Hive 写入数据之后,检测文件大小并触发一次额外的合并作业,将过小的文件合并成大文件。

1. hive.merge.mapfiles
sql 复制代码
set hive.merge.mapfiles = true;
  • 作用 :对于Map-only 任务(没有 Reduce 阶段)产生的输出,自动合并小文件。

  • 场景 :比如简单的 INSERT ... SELECT ... 不涉及 Shuffle,或用了动态分区写入但只有 Mapper,结束后检查输出文件,若平均大小过小则启动合并作业。

2. hive.merge.mapredfiles
sql 复制代码
set hive.merge.mapredfiles = true;
  • 作用 :对于MapReduce 任务(包含 Reduce 阶段)产生的输出,自动合并小文件。

  • 场景:大多数查询都有 Shuffle,即 Reduce 任务产生最终文件。该参数控制是否在 Reduce 结束后对输出目录进行小文件合并。通常两个参数都设为 true,以覆盖所有作业类型。

3. hive.merge.smallfiles.avgsize
sql 复制代码
set hive.merge.smallfiles.avgsize=160000000;  -- 160 MB
  • 作用 :触发合并的阈值 。当作业输出文件的平均大小低于这个值时,Hive 才会认为存在小文件问题,并启动合并作业。如果平均大小已高于该值,则不会合并。

  • 理解:这里设为 160 MB,意味着如果最终平均文件大小 ≥ 160 MB,就认为文件大小合理,无需合并。

4. hive.merge.size.per.task
sql 复制代码
set hive.merge.size.per.task = 256000000;  -- 256 MB
  • 作用 :合并作业执行时,每个 Mapper 任务期望生成的文件大小

  • 原理 :合并作业本质上是再读一遍输出数据(只有 Map 阶段),然后按这个大小写入新文件。比如合并 1 GB 的小文件,会产出约 1024 MB / 256 MB ≈ 4 个文件。

  • 效果:直接决定了合并后的最终文件大小。设得越大会使文件数越少。

输出端总结

作业结束时,如果文件平均大小低于 160 MB,则触发一个 Map-only 合并作业,按每个任务 256 MB 输出,将小文件重写为数量更少、体积更大的文件。

参考:大多数开发人员都弄错的Hive与MapReduce小文件合并问题