9.7.3 使用Hadoop归档文件
在9.2节中介绍过,每个文件HDFS采用块方式进行存储,在系统运行时,文件块的元数据信息会被存储在NameNode的内存中,因此,对HDFS来说,大规模存储小文件显然是低效的,很多小文件会耗尽NameNode的大部分内存。
Hadoop归档文件和HAR文件可以将文件高效地放入HDFS块中的文件存档设备,在减少NameNode内存使用的同时,仍然允许对文件进行透明访问。具体来说,Hadoop归档文件可以作为MapReduce的输入。这里需要注意的是,小文件并不会占用太多的磁盘空间,比如设定一个128MB的文件块来存储1MB的文件,实际上存储这个文件只需要1MB磁盘空间,而不是128MB。
Hadoop归档文件是通过archive命令工具根据文件集合创建的。因为这个工具需要运行一个MapReduce来并行处理输入文件,所以需要一个运行MapReduce的集群。而HDFS中有些文件是需要进行归档的,例如:
hadoop fs-lsr/user/ubuntu/In/
-rw-r—r—3 ubuntu\ubuntu supergroup 13 2012-03-18 20:15/user/ubuntu/In/hello.c.txt
-rw-r—r—1 ubuntu\ubuntu supergroup 13 2012-03-17 15:13/user/ubuntu/In/hello.txt
运行archive命令如下:
hadoop archive-archiveName files.har/user/ubuntu/In//user/ubuntu/
12/03/18 20:46:47 INFO mapred.JobClient:Running job:job_201010182044_0001
12/03/18 20:46:48 INFO mapred.JobClient:map 0%reduce 0%
12/03/18 20:47:21 INFO mapred.JobClient:map 100%reduce 0%
12/03/18 20:47:39 INFO mapred.JobClient:map 100%reduce 100%
12/03/18 20:47:41 INFO mapred.JobClient:Job complete:job_201010182044_0001
12/03/18 20:47:41 INFO mapred.JobClient:Counters:17
12/03/18 20:47:41 INFO mapred.JobClient:Job Counters
12/03/18 20:47:41 INFO mapred.JobClient:Launched reduce tasks=1
12/03/18 20:47:41 INFO mapred.JobClient:Launched map tasks=1
12/03/18 20:47:41 INFO mapred.JobClient:FileSystemCounters
12/03/18 20:47:41 INFO mapred.JobClient:FILE_BYTES_READ=540
12/03/18 20:47:41 INFO mapred.JobClient:HDFS_BYTES_READ=531
12/03/18 20:47:41 INFO mapred.JobClient:FILE_BYTES_WRITTEN=870
12/03/18 20:47:41 INFO mapred.JobClient:HDFS_BYTES_WRITTEN=305
12/03/18 20:47:41 INFO mapred.JobClient:Map-Reduce Framework
12/03/18 20:47:41 INFO mapred.JobClient:Reduce input groups=6
12/03/18 20:47:41 INFO mapred.JobClient:Combine output records=0
12/03/18 20:47:41 INFO mapred.JobClient:Map input records=6
12/03/18 20:47:41 INFO mapred.JobClient:Reduce shuffle bytes=0
12/03/18 20:47:41 INFO mapred.JobClient:Reduce output records=0
12/03/18 20:47:41 INFO mapred.JobClient:Spilled Records=12
12/03/18 20:47:41 INFO mapred.JobClient:Map output bytes=280
12/03/18 20:47:41 INFO mapred.JobClient:Map input bytes=399
12/03/18 20:47:41 INFO mapred.JobClient:Combine input records=0
12/03/18 20:47:41 INFO mapred.JobClient:Map output records=6
12/03/18 20:47:41 INFO mapred.JobClient:Reduce input records=6
在命令行中,第一个参数是归档文件的名称,这里是file.har文件;第二个参数是要归档的文件源,这里我们只归档一个源文件夹,即HDFS下/user/ubuntu/In/中的文件,但事实上,archive命令可以接收多个文件源;最后一个参数,即本例中的/user/ubuntu/是HAR文件的输出目录。可以看到这个命令的执行流程为一个MapRedeuce任务。
下面我们来看这个归档文件是怎么创建的:
hadoop fs-ls/user/ubuntu/In//user/ubuntu/
Found 2 items
-rw-r—r—3 ubuntu\ubuntu supergroup 13 2012-03-18 20:15/user/ubuntu/In/hello.c.txt
-rw-r—r—1 ubuntu\ubuntu supergroup 13 2012-03-17 15:13/user/ubuntu/In/hello.txt
Found 3 items
drwxr-xr-x-ubuntu\ubuntu supergroup 0 2012-03-18 20:15/user/ubuntu/In
drwxr-xr-x-ubuntu\ubuntu supergroup 0 2012-03-18 18:53/user/ubuntu/ubuntu
drwxr-xr-x-ubuntu\ubuntu supergroup 0 2012-03-18 20:47/user/ubuntu/files.har
这个目录列表展示了一个HAR文件的组成:两个索引文件和部分文件(part file)的集合。这里的部分文件包含已经连接在一起的大量源文件的内容,同时索引文件可以检索部分文件中的归档文件,包括它的长度、起始位置等。但是,这些细节在使用HAR URI模式访问HAR文件时多数都是隐藏的。HAR文件系统是建立在底层文件系统上的(此处是HDFS),以下命令以递归的方式列出了归档文件中的文件:
hadoop fs-lsr har:///user/ubuntu/files.har
drw-r—r—-ubuntu\ubuntu supergroup 0 2012-03-18 20:47/user/ubuntu/files.har/user
drw-r—r—-ubuntu\ubuntu supergroup 0 2012-03-18 20:47/user/ubuntu/files.har/
user/ubuntu
drw-r—r—-ubuntu\ubuntu supergroup 0 2012-03-18 20:47/user/ubuntu/files.har/
user/ubuntu/In
-rw-r—r—10 ubuntu\ubuntu supergroup 13 2012-03-18 20:47/user/ubuntu/files.
har/user/ubuntu/In/hello.c.txt
-rw-r—r—10 ubuntu\ubuntu supergroup 13 2012-03-18 20:47/user/ubuntu/files.
har/user/ubuntu/In/hello.txt
如果HAR文件所在的文件系统是默认的文件系统,那么这里的内容就非常直观和易懂,但是,如果你想要在其他文件系统中使用HAR文件,就需要使用不同格式的URI路径。下面两个命令即具有相同的作用:
hadoop fs-lsr har:///user/ubuntu/files.har/my/files/dir
hadoop fs-lsr har://hdfs-localhost:8020/user/ubuntu/files.har/my/files/dir
第二个命令,它仍然使用HAR模式描述一个HAR文件系统,但是使用HDFS作为底层的文件系统模式,HAR模式之后紧跟一个HDFS系统的主机和端口号。HAR文件系统会将HAR URI转换为底层的文件系统访问URI。在本例中即为hdfs://localhost:8020/user/ubuntu/archive/files.har,文件的剩余部分路径即为文件归档部分的路径/my/files/dir。
想要删除HAR文件,需要使用删除的递归格式,这是因为底层的文件系统HAR文件是一个目录,删除命令为hadoop fs-rmr/user/ubuntu/files.har。
对于HAR文件我们还需要了解它的一些不足。当创建一个归档文件时,还会创建原始文件的一个副本,这样就需要额外的磁盘空间(尽管归档完成后会删除原始文件)。而且当前还没有针对归档文件的压缩方法,只能对写入归档文件的原始文件进行压缩。归档文件一旦创建就不能改变,要增加或者删除文件,就要重新创建。事实上,这对于那些写后不能更改的文件不构成问题,因为可以按日或者按周进行定期成批归档。
如前所述,HAR文件可以作为MapReduce的一个输入文件,然而,没有一个基于归档的InputFormat可以将多个文件打包到一个单一的MapReduce中去。所以,即使是HAR文件,处理小的文件时效率仍然不高。