如果您将增加内存并将文件存储在 HDFS 中。在此之后,您将在处理时遇到许多问题。
小文件和 HDFS 的问题
小文件是明显小于 HDFS 块大小(默认 64MB)的文件。如果您要存储小文件,那么您可能有很多文件(否则您不会转向 Hadoop),问题是 HDFS 无法处理大量文件。
HDFS 中的每个文件、目录和块都表示为 namenode 内存中的一个对象,根据经验,每个对象占用 150 个字节。因此,1000 万个文件,每个文件使用一个块,将使用大约 3 GB 的内存。扩大到这个水平是当前硬件的一个问题。当然十亿个文件是不可行的。
此外,HDFS 并不适合高效访问小文件:它主要是为大文件的流式访问而设计的。读取小文件通常会导致大量的搜索和从数据节点到数据节点的大量跳跃来检索每个小文件,所有这些都是低效的数据访问模式。
小文件和 MapReduce 的问题
Map 任务通常一次处理一个输入块(使用默认的 FileInputFormat)。如果文件非常小并且数量很多,那么每个 map 任务处理的输入非常少,并且有很多 map 任务,每个任务都会带来额外的簿记开销。比较一个分成 16 个 64MB 块的 1GB 文件和 10,000 个左右 100KB 的文件。10,000 个文件每个都使用一张地图,作业时间可能比使用单个输入文件的同等文件慢几十或几百倍。
有几个特性可以帮助减轻簿记开销:任务 JVM 重用以在一个 JVM 中运行多个映射任务,从而避免一些 JVM 启动开销(请参阅 mapred.job.reuse.jvm.num.tasks 属性)和 MultiFileInputSplit每张地图可以运行多个拆分。
解决方案
Hadoop 档案(HAR 文件)
创建.HAR
文件 Hadoop 存档(HAR 文件)在 0.18.0 中被引入 HDFS,以缓解大量文件对 namenode 内存造成压力的问题。HAR 文件通过在 HDFS 之上构建分层文件系统来工作。使用 hadoop archive 命令创建一个 HAR 文件,该命令运行 MapReduce 作业以将正在归档的文件打包成少量 HDFS 文件
hadoop archive -archiveName name -p <parent> <src>* <dest>
hadoop archive -archiveName foo.har -p /user/hadoop dir1 dir2 /user/zoo
序列文件
对“小文件问题”问题的通常回答是:使用 SequenceFile。这里的想法是使用文件名作为键,文件内容作为值。这在实践中非常有效。回到 10,000 个 100KB 的文件,您可以编写一个程序将它们放入单个 SequenceFile,然后您可以在 SequenceFile 上以流式方式(直接或使用 MapReduce)处理它们。还有一些奖金。SequenceFile 是可拆分的,因此 MapReduce 可以将它们分成块并独立地对每个块进行操作。与 HAR 不同,它们也支持压缩。在大多数情况下,块压缩是最好的选择,因为它压缩了多条记录的块(而不是每条记录)
HBase
如果您要生成大量小文件,则根据访问模式,不同类型的存储可能更合适。HBase 将数据存储在 MapFiles(索引 SequenceFiles)中,如果您需要偶尔随机查找进行 MapReduce 风格的流式分析,这是一个不错的选择。如果延迟是一个问题,那么还有很多其他选择