【问题标题】:Large number of small files Hadoop大量小文件Hadoop
【发布时间】:2026-01-04 19:35:01
【问题描述】:

一些机器的参数是通过网络服务测量并上传到HDFS的。每次测量的参数值都保存在一个文件中,其中一次测量平均有 1000 个值。

问题是 - 有大量文件。 MapReduce 作业仅使用一定数量的文件(例如,上个月的测量值)。因此,我无法将它们全部合并到一个大的序列文件中,因为在不同的时间需要不同的文件。

我知道拥有大量小文件是不好的,因为 NameNode 包含 HDFS 上所有这些文件的路径(并将其保存在其内存中),另一方面,每个小文件都会生成一个 Mapper创作。

如何避免这个问题?

【问题讨论】:

  • 您是否尝试使用CombineSequenceFileInputFormat?它应该将小文件合并为一个拆分并创建较少数量的映射器。文档:hadoop.apache.org/docs/stable/api/org/apache/hadoop/mapreduce/…
  • 说实话,我对 Hadoop 不是很有经验,但我知道这种方法可能存在一些问题。例如,对 HDFS 上所有文件的引用仍会保存在 NameNode 内存中,对吗?使用 CombineSequenceFileInputFormat 时是否还有其他问题?
  • 是的,在 HDFS 中存储大量小文件是个坏主意。您可以每小时(或每天)将小文件合并为一个序列文件。如果您将使用文件的时间戳作为键和文件的内容作为值,那么在映射器中,您将能够过滤不包括在指定时间范围内的文件。
  • 所以您建议运行 MapReduce 作业并仅从映射器发出指定范围内的文件?但是我仍然会遇到该工作的许多映射器任务的问题,我想这样的事情可以容忍吗?另一方面,我需要将原始文件保留在 HDFS 上,以便下次需要时合并它们,这将一直对 NameNode 产生影响。对此有何评论?如果没有更好的解决方案,我想我将不得不做类似的事情。您如何看待使用 HBase 或类似的东西按时间戳查询?会不会存在同样的问题?
  • 你可以尝试 HAR(hadoop archive) 将小文件打包到单个归档中,以减少 NameNode 维护过多小文件的开销,并使用 CombineFileInputFormat over HAR 来限制调度的映射器数量。

标签: hadoop


【解决方案1】:

迟到的答案:您可以使用 SeaweedFS https://github.com/chrislusf/seaweedfs(我正在处理这个问题)。对大量小文件进行了特殊优化。

HDFS 实际上很好地支持将文件存储委托给其他文件系统。只需添加一个 SeaweedFS hadoop jar。见https://github.com/chrislusf/seaweedfs/wiki/Hadoop-Compatible-File-System

【讨论】:

    【解决方案2】:

    您可以将所需文件连接到一个临时文件中,一旦分析该文件就会被删除。我认为您可以在脚本中非常轻松地创建它。

    不管怎样,做个数字:这么大的文件也会被分成几块大小为块大小的块(dfs.blocksize 参数a hdfs-defaul.xml),这些块中的每一个都将分配给一个映射器。我的意思是,根据块大小和平均“小文件”大小,增益可能不是那么大。

    【讨论】:

    • 嗯,增益应该很大,因为文件可能有 8KB 的大小,而默认的块大小是 64MB。
    • 所以,我认为你的连接脚本必须很聪明:你必须连接小文件至少直到达到块大小。
    • 感谢您的建议,但我想避免在每次需要执行作业时连接大量文件。但是,另一方面,我可能每次都需要不同的文件子集......(例如,如果作业在八小时后开始,它需要同时添加的文件并且它不需要来自窗口大小的文件- 8 小时)。