出于测试目的,我正在尝试将大量小文件加载到HDFS中。实际上我们谈论的是1百万(1'000'000)个文件,大小从1KB到100KB。我在一个文件夹中的Linux系统上使用R脚本生成了这些文件。每个文件都有一个信息结构,其中包含带有产品信息的标题和带有数字信息的不同列数。
问题是当我尝试使用以下命令将这些本地文件上传到HDFS时:
hdfs dfs -copyFromLocal /home/user/Documents/smallData /
然后我得到以下Java-Heap-Size错误之一:
线程“main”中的异常java.lang.OutOfMemoryError:Java堆空间
线程“main”中的异常java.lang.OutOfMemoryError:超出GC开销限制
我使用Cloudera CDH5发行版,Java-Heap-Size约为5 GB。除了增加Java-Heap-Size之外还有其他方法吗?也许更好的方法是将大量数据加载到HDFS中?
非常感谢每一条有用的评论!
答案 0 :(得分:0)
答案 1 :(得分:0)
首先:如果这不是对你的名字节进行压力测试,那么建议不要这样做。但我猜你知道你在做什么。 (预计此进展缓慢)
如果目标只是获取HDFS上的文件,请尝试以较小批量执行此操作,或在hadoop 客户端上设置更高的堆大小。
您可以通过在HADOOP_HEAPSIZE=<mem in Mb here>
命令前添加hadoop -put
作为答案中的 rpc1 来执行此操作。
答案 2 :(得分:0)
Hadoop分布式文件系统不适用于许多小文件,但有许多大文件。 HDFS在查找表中保留记录,该表指向HDFS中的每个文件/块,并且此查找表通常加载到内存中。所以你不应该只增加java堆大小,而且还要增加hadoop-env.sh中名称节点的堆大小,这是默认值:
export HADOOP_HEAPSIZE=1000
export HADOOP_NAMENODE_INIT_HEAPSIZE="1000"
如果你要对这些文件进行处理,你应该期望在你运行的第一个MapReduce作业上性能低下(Hadoop会创建一些map任务作为文件/块的数量,这会使你的系统超载,除非你使用combineinputformat)。建议您将文件合并为大文件(64MB / 128MB)或使用其他数据源(不是HDFS)。
答案 3 :(得分:0)
如果您要增加内存并将文件存储在HDFS中。在此之后,您将在处理时遇到许多问题。
Problems with small files and HDFS
小文件是一个明显小于HDFS块大小的文件(默认为64MB)。如果你要存储小文件,那么你可能有很多文件(否则你不会转向Hadoop),问题是HDFS无法处理大量文件。
HDFS中的每个文件,目录和块都表示为namenode内存中的一个对象,根据经验,每个对象占用150个字节。因此,每个使用一个块的1000万个文件将使用大约3千兆字节的内存。超出此级别的扩展是当前硬件的问题。当然十亿个文件是不可行的。
此外,HDFS并不适合有效地访问小文件:它主要用于大型文件的流式访问。通过读取小文件通常会导致大量搜索和从datanode到datanode的大量跳转以检索每个小文件,所有这些都是低效的数据访问模式。
Problems with small files and MapReduce
Map任务通常一次处理一个输入块(使用默认的FileInputFormat)。如果文件很小并且有很多文件,那么每个地图任务处理的输入都很少,而且还有更多的地图任务,每个任务都会增加额外的簿记开销。将1GB文件分成16个64MB块和10,000个左右100KB文件。 10,000个文件各使用一个映射,作业时间比单个输入文件的等效数据慢几十或几百倍。
有一些功能可以帮助减轻簿记开销:任务JVM重用以在一个JVM中运行多个映射任务,从而避免一些JVM启动开销(请参阅mapred.job.reuse.jvm.num.tasks属性)和MultiFileInputSplit,每个地图可以运行多个分割。
SOLUTION
创建.HAR
文件
Hadoop Archives(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
接下来是
Sequence Files
对“小文件问题”问题的通常回答是:使用SequenceFile。这里的想法是你使用文件名作为键,文件内容作为值。这在实践中非常有效。回到10,000个100KB文件,您可以编写一个程序将它们放入一个SequenceFile中,然后您可以在SequenceFile上以流式方式(直接或使用MapReduce)处理它们。还有一些奖金。 SequenceFiles是可拆分的,因此MapReduce可以将它们分成块并独立地对每个块进行操作。与HARs不同,它们也支持压缩。在大多数情况下,块压缩是最佳选择,因为它压缩了几个记录(而不是每个记录)的块
HBase
如果要生成大量小文件,那么根据访问模式,不同类型的存储可能更合适。 HBase将数据存储在MapFiles(索引的SequenceFiles)中,如果您需要偶尔随机查找MapReduce样式流分析,这是一个不错的选择。如果延迟是一个问题,那么还有很多其他选择
答案 4 :(得分:0)
为了解决这个问题,我用一些格式构建了一个文件。文件的内容都是小文件。格式如下:
<DOC>
<DOCID>1</DOCID>
<DOCNAME>Filename</DOCNAME>
<DOCCONTENT>
Content of file 1
</DOCCONTENT>
</DOC>
这种结构可能或多或少都是领域,但这个想法是一样的。例如,我使用了这个结构:
<DOC>
<DOCID>1</DOCID>
Content of file 1
</DOC>
处理更多600万个文件。
如果您希望处理一个地图任务的每个文件,您可以删除\ n之间的字符和标记。在此之后,您只需解析结构并具有文档标识符和内容。