hadoop小文件解决方案

一、 概述

   小文件是指文件size小于HDFS上block大小的文件。这样的文件会给Hadoop的扩展性和性能带来严重问题。首先,在HDFS中,任何block,文件或者目录在内存中均以对象的形式存储,每个对象约占150byte,如果有1000 0000个小文件,每个文件占用一个block,则namenode大约需要2G空间。如果存储1亿个文件,则namenode需要20G空间。这样namenode内存容量严重制约了集群的扩展。 其次,访问大量小文件速度远远小于访问几个大文件。HDFS最初是为流式访问大文件开发的,如果访问大量小文件,需要不断的从一个datanode跳到另一个datanode,严重影响性能。最后,处理大量小文件速度远远小于处理同等大小的大文件的速度。每一个小文件要占用一个slot,而task启动将耗费大量时间甚至大部分时间都耗费在启动task和释放task上。

 

二、Hadoop自带的解决方案

对于小文件问题,Hadoop本身也提供了几个解决方案,分别为:Hadoop Archive,Sequence file和CombineFileInputFormat。

(1) Hadoop Archive

Hadoop Archive或者HAR,是一个高效地将小文件放入HDFS块中的文件存档工具,它能够将多个小文件打包成一个HAR文件,这样在减少namenode内存使用的同时,仍然允许对文件进行透明的访问。

使用HAR时需要两点,第一,对小文件进行存档后,原文件并不会自动被删除,需要用户自己删除;第二,创建HAR文件的过程实际上是在运行一个mapreduce作业,因而需要有一个Hadoop集群运行此命令。

该方案需人工进行维护,适用管理人员的操作,而且har文件一旦创建,Archives便不可改变,不能应用于多用户的互联网操作。

创建文件 hadoop archive -archiveName xxx.har -p  /src  /dest
查看内部结构 hadoop fs -lsr /dest/xxx.har
查看内容 hadoop fs -lsr har:///dest/xxx.har

(2) Sequence file

sequence file由一系列的二进制key/value组成,如果为key小文件名,value为文件内容,则可以将大批小文件合并成一个大文件。

Hadoop-0.21.0中提供了SequenceFile,包括Writer,Reader和SequenceFileSorter类进行写,读和排序操作。如果hadoop版本低于0.21.0的版本,实现方法可参见[3]。

 

该方案对于小文件的存取都比较自由,不限制用户和文件的多少,但是SequenceFile文件不能追加写入,适用于一次性写入大量小文件的操作,支持压缩。

 

Configurationconf=new Configuration();
FileSystemfs=FileSystem.get(conf);
PathseqFile=new Path("seqFile.seq");
//Reader内部类用于文件的读取操作
SequenceFile.Readerreader=new SequenceFile.Reader(fs,seqFile,conf);
//Writer内部类用于文件的写操作,假设Key和Value都为Text类型
SequenceFile.Writerwriter=new SequenceFile.Writer(fs,conf,seqFile,Text.class,Text.class);
//通过writer向文档中写入记录
writer.append(newText("key"),new Text("value"));
IOUtils.closeStream(writer);//关闭write流
//通过reader从文档中读取记录
Textkey=new Text();
Textvalue=new Text();
while(reader.next(key,value)){
  System.out.println(key);
  System.out.println(value);
}
IOUtils.closeStream(reader);//关闭read流
Configuration conf=new Configuration();
FileSystem fs=FileSystem.get(conf);
Path mapFile=new Path("mapFile.map");

//Writer内部类用于文件的写操作,假设Key和Value都为Text类型
MapFile.Writer writer=new MapFile.Writer(conf,fs,mapFile.toString(),Text.class,Text.class);

//通过writer向文档中写入记录
//与SequenceFile不同的是,MapFile的KeyClass一定要实现WritableComparable接口,即Key值是可比较的。
writer.append(new Text("key"),new Text("value"));
IOUtils.closeStream(writer);//关闭write流

//Reader内部类用于文件的读取操作
MapFile.Reader reader=new MapFile.Reader(fs,mapFile.toString(),conf);

//通过reader从文档中读取记录
Text key=new Text();
Text value=new Text();
while(reader.next(key,value)){
	System.out.println(key);
	System.out.println(key);
}
IOUtils.closeStream(reader);//关闭read流

(3)CombineFileInputFormat

CombineFileInputFormat是一种新的inputformat,用于将多个文件合并成一个单独的split,另外,它会考虑数据的存储位置。

该方案版本比较老,网上资料甚少,从资料来看应该没有第二种方案好。

三、小文件问题解决方案

在原有HDFS基础上添加一个小文件处理模块,具体操作流程如下:

       1.   当用户上传文件时,判断该文件是否属于小文件,如果是,则交给小文件处理模块处理,否则,交给通用文件处  理模块处理。

       2.  在小文件模块中开启一定时任务,其主要功能是当模块中文件总size大于HDFS上block大小的文件时,则通过SequenceFile组件以文件名做key,相应的文件内容为value将这些小文件一次性写入hdfs模块。

       3. 同时删除已处理的文件,并将结果写入数据库。

       4.  当用户进行读取操作时,可根据数据库中的结果标志来读取文件。

你可能感兴趣的:(hadoop,hdfs)