Hadoop合并小文件,Hadoop合并文件
在运行hadoop程序时,从hdfs上读取数据,可能会由于小文件过多而影响内存资源大量被占用,从而导致hadoop集群崩溃,或者程序执行耗时过长。(在Hadoop的世界中,小文件是指文件大小远远小于HDFS块大小的文件,Hadoop2.0中,HDFS默认的块大小是128MB,所以,比如2MB,7MB或9MB的文件就认为是小文件。)
Hadoop的应用中,Hadoop可以很好的处理大文件,不过当文件很多,并且文件很小时,Hadoop会把每一个小文件传递给map()函数,而Hadoop在调用map()函数时会创建一个映射器,这样就会创建了大量的映射器,应用的运行效率并不高。例如,如果有2000个文件,每一个文件的大小约为2-3MB,在处理这一批文件时,就需要2000个映射器,将每一个文件发送到一个映射器,效率会非常低的。所以,在Hadoop的环境环境中,要解决这个问题,就需要把多个文件合并为一个文件,然后在进行处理。Hadoop主要设计批处理大量数据的大文件,不是很多小文件。解决小文件问题的主要目的就是通过合并小文件为更大的文件来加快Hadoop的程序的执行,解决小文件问题可以减少map()函数的执行次数,相应地提高hadoop作业的整体性能。
解决方法:
将小文件提交到MapReduce/Hadoop之前,需要先把这些小文件合并到大文件中,再把合并的大文件提交给MapReduce驱动器程序。
定义一个SmallFilesConsolidator类接受一组小文件,然后将这些小文件合并在一起,生成更大的Hadoop文件,这些文件的大小接近于HDFS块大小(dfs.block.size),最优的解决方案便是尽可能创建少的文件。
定义一个BucketThread类,这个类把小文件合并为一个大小于或接近于HDFS块大小的大文件。BucketThread是一个实现了Runable接口的独立线程,通过提供copyMerge()方法,把小文件合并为一个大文件。由于BucketThread是一个线程,所有的BucketThread对象可以并发的合并小文件。copyMerge()是BucketThread类的核心方法,它会把一个桶中的所有小文件合并为为一个临时的HDFS文件。例如,如果一个同种包含小文件{file1,file2,file3,file4,file5},那么合并得到的文件如下图所示:
SmallFilesConsolidator类的实现