Hadoop小文件问题及解决方案 2015-07-15 22:00

小文件存在的问题

HDFS存储小文件的问题

小文件是指那些文件大小比HDFS block size(默认64M)小很多的文件。每个小文件即使size很小,仍旧会占用一个block。HDFS中每一个文件、目录或是block在namenode的内存中都对应一个对象,每个对象占用150个字节。因此,一千万个小文件,每个占用一个block,那么namenode就要消耗大约2G的内存。如果有更多的小文件,意味着namenode需要消耗更多的内存,而现有的计算机硬件可能会难以满足相应需求,且会导致集群难以扩展。

另外,HDFS并不是为了有效地访问小文件而设计的:其初衷是为了流式访问大文件。如果访问大量小文件,需要执行大量的seeks操作,并需要不断地从一个datanode跳到另一个datanode,从而获取每个小文件,然而,上述每个操作都是低效的数据访问方式。

MapReduce处理小文件的问题

Map tasks通常是以block为单位进行数据的处理。如果文件非常小且文件数量极大,那么每个map task处理的数据就非常少,且需要启动大量的map tasks,而记录每个map task信息(bookkeeping)也需要一定的开销。举个例子:一个是单独的1GB的文件,在HDFS中存储到16个64MB blocks;另一个是10000个100KB的小文件,大约共1GB。这10000个文件每个都用一个map task处理,那么处理这些文件所需的时间要比第一种情况慢上十倍甚至百倍。

Hadoop提供了一些方法用于减少bookkeeping带来的开销:设置mapred.job.reuse.jvm.num.tasks属性,允许一个JVM同时执行多个map tasks,以这种重用task JVM的方式减少启动多个JVM的开销;使用MultiFileInputSplit,每个map task可处理多个blocks数据。

PS: bookkeeping是指在一个job的初始化阶段记录每个task的状态和进度。

解决方案

  • HAR文件方案
  • Sequence File方案
  • CombineFileInputFormat方案
  • MapFile方案
  • HBase方案

HAR文件方案

为了缓解大量小文件带给namenode内存的压力,Hadoop 0.18.0引入了Hadoop Archives(HAR files),其本质就是在HDFS之上构建一个分层文件系统。通过执行hadoop archive命令就可以创建一个HAR文件。在命令行下,用户可使用一个以har://开头的URL就可以访问HAR文件中的小文件。使用HAR files可以减少HDFS中的文件数量。

下图为HAR文件的文件结构,可以看出来访问一个指定的小文件需要访问两层索引文件才能获取小文件在HAR文件中的存储位置,因此,访问一个HAR文件的效率可能会比直接访问HDFS文件要低。对于一个MapReduce任务来说,如果使用HAR文件作为其输入,仍旧是其中每个小文件对应一个Map task,效率低下。所以,HAR files最好是用于文件归档。

HAR文件使用使用

将HDFS /tmp/test目录下的所有内容打包成HAR文件:

hadoop archive -archiveName blog_file.har -p /tmp/test /tmp/

查看打包后的HAR文件内容:

hdfs dfs -ls har:/tmp/blog_file.har
Found 9 items
drwxr-xr-x   - root supergroup          0 2015-07-15 11:53 har:///tmp/blog_file.har/blog_file.har
-rw-r--r--   3 root supergroup         58 2015-07-15 11:50 har:///tmp/blog_file.har/ejabberd.txt
-rw-r--r--   3 root supergroup         54 2015-07-15 11:50 har:///tmp/blog_file.har/flume.txt
-rw-r--r--   3 root supergroup        548 2015-07-15 11:50 har:///tmp/blog_file.har/hbase.txt
-rw-r--r--   3 root supergroup        740 2015-07-15 11:50 har:///tmp/blog_file.har/hive_ha.txt
-rw-r--r--   3 root supergroup         53 2015-07-15 11:50 har:///tmp/blog_file.har/namenode_ha
-rw-r--r--   3 root supergroup       2802 2015-07-15 11:50 har:///tmp/blog_file.har/small_file.txt
-rw-r--r--   3 root supergroup       1352 2015-07-15 11:50 har:///tmp/blog_file.har/sqoop2.txt
drwxr-xr-x   - root supergroup          0 2015-07-15 11:50 har:///tmp/blog_file.har/zookeeper

查看HAR文件中的小文件:

hdfs dfs -cat har:/tmp/blog_file.har/namenode_ha

Sequence Files方案

除了HAR files,另一种可选是SequenceFile,其核心是以文件名为key、文件内容为value组织小文件。回到之前提到的10000个100KB大小的文件,你可以编写程序将这些文件放到一个SequenceFile文件,然后就以数据流的方式处理这些文件,也可以使用MapReduce进行处理。一个SequenceFile是可分割的,所以MapReduce可将文件切分成块,每一块独立操作。不像HARs,SequenceFile支持压缩。在大多数情况下,以block为单位进行压缩是最好的选择,因为一个block包含多条记录,压缩作用在block之上,比Record压缩方式(一条一条记录进行压缩)的压缩比高。

把已有的数据转存为SequenceFile比较慢。比起先写小文件,再将小文件写入SequenceFile,一个更好的选择是直接将数据写入一个SequenceFile文件,省去小文件作为中间媒介。

下图为SequenceFile的文件结构。HAR files可以列出所有keys,但是SequenceFile是做不到的,因此,在访问时,只能从文件头顺序访问。

HBase方案

HBase也可用于存储小文件,将文件内容(数据)作为一个字段的值直接写入HBase中。前提是文件真的很小。

方案比较

  • 如果文件大小能保证在一个较小的范围内,使用HBase
  • 如果小文件是每天都产生,那么可以考虑使用HAR files或者SequenceFile(或基于其的方式,如MapFile),并将源文件删除,在HBase中存储实际地址。

如果用户需要通过HBase中的地址访问存储在HDFS中的小文件,那么就需要写相关服务来提供该功能了。

参考文档

  1. Hadoop小文件问题
  2. Hadoop小文件优化
  3. Hadoop小文件问题及解决方案
  4. 一种基于混合索引的HDFS小文件存储策略
  5. Hadoop Archives Guide
Tags: #HDFS    Post on Hadoop