-
大量小文件的存在势必占用大量的 NameNode 内存
HDFS 中的每一个文件、目录以及文件块,在 NameNode 内存都会有记录,每一条记录大约占用150字节的内存空间(该大小与文件、目录及文件块的大小无关),namenode的内存就会成为HDFS 的横向扩展能力的一个限制因素。 -
如果我们使用 MapReduce 任务来处理这些小文件,因为每个 Map 会处理一个 HDFS 块;这会导致程序启动大量的 Map 来处理这些小文件,( 读取小文件数据的任务执行时,消耗过多的集群资源。因为map task在执行的时候一般只处理1个文件,如果这个时候要读取的文件过多,就会造成大量的map task启动。) 虽然这些小文件总的大小并非很大,却占用了集群的大量资源!
- **实时流处理:**比如我们使用 Spark Streaming 从外部数据源接收数据,然后经过 ETL 处理之后存储到 HDFS 中。这种情况下在每个 Job 中会产生大量的小文件。
- **MapReduce 产生:**我们使用 Hive 查询一张含有海量数据的表,然后存储在另外一张表中,而这个查询只有简单的过滤条件(比如 select * from iteblog where from = ‘hadoop’),这种情况只会启动大量的 Map 来处理,这种情况可能会产生大量的小文件。也可能 Reduce 设置不合理,产生大量的小文件。
- **数据本身的特点:**比如我们在 HDFS 上存储大量的图片、短视频、短音频等文件,由于这些文件的特点,而且数量众多,也可能给 HDFS 大量灾难。
分别为:Hadoop Archive,Sequence file和CombineFileInputFormat。
(1)Hadoop ArchiveHadoop Archive或者HAR,是一个高效地将小文件放入HDFS块中的文件存档工具,它能够将多个小文件打包成一个HAR文件,这样在减少namenode内存使用的同时,仍然允许对文件进行透明的访问。
从上图我们可以看出,Hadoop在归档文件时通过二层索引文件的查找,进行最终文件的读取。所以在效率上会比普通HDFS读取文件慢一些。
对某个目录/foo/bar下的所有小文件存档成/outputdir/ zoo.har:
hadoop archive -archiveName zoo.har -p /foo/bar /outputdir
当然,也可以指定HAR的大小(使用-Dhar.block.size)。
HAR是在Hadoop file system之上的一个文件系统,因此所有fs shell命令对HAR文件均可用,只不过是文件路径格式不一样,HAR的访问路径可以是以下两种格式:
har://scheme-hostname:port/archivepath/fileinarchive
har:///archivepath/fileinarchive(本节点)
可以这样查看HAR文件存档中的文件:
hadoop dfs -ls har:///user/zoo/foo.har
输出:
har:///user/zoo/foo.har/hadoop/dir1
har:///user/zoo/foo.har/hadoop/dir2
创建存档文件的问题:
1、存档文件的源文件目录以及源文件都不会自动删除需要手动删除
2、存档的过程实际是一个mapreduce过程,所以需要需要hadoop的mapreduce的支持
3、存档文件本身不支持压缩
4、存档文件一旦创建便不可修改,要想从中删除或者增加文件,必须重新建立存档文件
5、创建存档文件会创建原始文件的副本,所以至少需要有与存档文件容量相同的磁盘空间
6、要归档的文件名中不能有空格,否则会抛出异常,可以将空格用其他符号替换(使用-Dhar.space.replacement.enable=true 和-Dhar.space.replacement参数)。
7、对于一个mapreduce任务来说,如果使用HAR文件作为其输入,仍旧是其中每个小文件对应一个map task,效率低下。所以,HAR files最好是用于文件归档。
sequence file由一系列的二进制key/value组成,其中key为小文件名,value为文件内容,则可以将大批小文件合并成一个大文件,通过改变文件的写出方式,写入到SequenceFile格式的文件中。这主要是因为SequenceFile独有的存储格式决定了它可以很好的满足小文件存储的需求。SequenceFile文件内部存储数据的方式是以下面key-value的形式拼接而成。
因为考虑到小文件中的内容少,在这里我们可以以文件名作为key,文件内容作为value,直接写到SequenceFile中。
通常对于"小文件问题"的回应会是:使用序列文件(SequenceFile)。这种方法的思路是,使用文件名(filename)作为key,并且文件内容(file contents)作为value。
将大量小文件放入一个单一的SequenceFile,流式处理 *** 作SequenceFile的两个优势:
- SequenceFiles是可拆分的,因此MapReduce可以将它们分成块并独立地对每个块进行 *** 作;
- 它们同时支持压缩,不像HAR。 在大多数情况下,块压缩是最好的选择,因为它将压缩几个记录为一个块,而不是一个记录压缩一个块。
CombineFileInputFormat是一种新的inputformat,用于将多个文件合并成一个单独的split。功能,是将一个目录(可能包括多个小文件,不包括子目录)作为一个map的输入,而不是通常使用一个文件作为输入。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)