Hadoop之-HDFS上大量小文件的问题及解决方案

前言


我们知道,HDFS 被设计成存储大规模的数据集,我们可以在 HDFS 上存储 TB 甚至 PB 级别的海量数据。而这些数据的元数据(比如文件由哪些块组成、这些块分别存储在哪些节点上)全部都是由 NameNode 节点维护,为了达到高效的访问, NameNode 在启动的时候会将这些元数据全部加载到内存中。而 HDFS 中的每一个文件、目录以及文件块,在 NameNode 内存都会有记录,每一条信息大约占用150字节的内存空间。由此可见,HDFS 上存在大量的小文件(这里说的小文件是指文件大小要比一个 HDFS 块大小(在 Hadoop1.x 的时候默认块大小64M,可以通过dfs.blocksize 来设置;但是到了 Hadoop 2.x 的时候默认块大小为128MB了,可以通过 dfs.block.size 设置) 小得多的文件。)至少会产生以下几个负面影响:

  • 大量小文件的存在势必占用大量的 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 大量灾难。

那么针对这些小文件,现有哪几种解决方案呢?

HDFS自带的小文件存储解决方案

对于小文件问题,hadoop自身提供了三种解决方案:Hadoop Archive(HRA---文件归档)、 Sequence File 和 CombineFileInputFormat


一、Hadoop Archive

文件归档在这里的意思是将文件再次进行整理和保存,使之更易管理和保存。而Hadoop中的归档是在HDFS之上又构建了一个新的抽象层,叫HAR(Hadoop Archives ),访问的格式变为了har:// URL。它的实现原理如下图

 

 

从上图我们可以看出,Hadoop在归档文件时通过二层索引文件的查找,进行最终文件的读取。所以在效率上会比普通HDFS读取文件慢一些。Hadoop归档文件可以通过 hadoop archive归档命令产生,归档文件产生后并不会删除原文件,此时可以由用户决定是否保留原始文件。归档文件是不可修改的,当执行删除,重命名操作时会抛出异常。Hadoop归档文件相关内容可以详细阅读官方地址:http://hadoop.apache.org/docs/current/hadoop-archives/HadoopArchives.html

创建存档文件的问题:
1、存档文件的源文件目录以及源文件都不会自动删除需要手动删除
2、存档的过程实际是一个mapreduce过程,所以需要需要hadoop的mapreduce的支持
3、存档文件本身不支持压缩
4、存档文件一旦创建便不可修改,要想从中删除或者增加文件,必须重新建立存档文件
5、创建存档文件会创建原始文件的副本,所以至少需要有与存档文件容量相同的磁盘空间


二、Sequence File

sequence file由一系列的二进制的对组成,其中key为小文件的名字,value的file content。通过改变文件的写出方式,写入到SequenceFile格式的文件中。这主要是因为SequenceFile独有的存储格式决定了它可以很好的满足小文件存储的需求。SequenceFile文件内部存储数据的方式是以下面key-value的形式拼接而成。

因为考虑到小文件中的内容少,在这里我们可以以文件名作为key,文件内容作为value,直接写到SequenceFile中

通常对于"小文件问题"的回应会是:使用序列文件(SequenceFile)。这种方法的思路是,使用文件名(filename)作为key,并且文件内容(file contents)作为value。在实践中这种方式非常有效。我们回到10,000个100KB小文件问题上,你可以编写一个程序将它们放入一个单一的SequenceFile,然后你可以流式处理它们(直接处理或使用MapReduce)操作SequenceFile。这样同时会带来两个优势:(1)SequenceFiles是可拆分的,因此MapReduce可以将它们分成块并独立地对每个块进行操作;(2)它们同时支持压缩,不像HAR。 在大多数情况下,块压缩是最好的选择,因为它将压缩几个记录为一个块,而不是一个记录压缩一个块。(Block compression is the best option in most cases, since it compresses blocks of several records (rather than per record))


三、CombineInputFormat

CombineInputFormat的功能,是将一个目录(可能包括多个小文件,不包括子目录)作为一个map的输入,而不是通常使用一个文件作为输入。

CombineInputFormat本身是个抽象类,要使用它,涉及:

1)CombineFileSplit

我们的目标是使得一个split不是属于一个文件,而是可能包含多个文件,所以这里不再使用常用的FileSplit,而是CombineFileSplit,包括了各个文件的路径、长度、读的起始位置等信息。CombineFileSplit是CombineInputFormat中getSplits()的对象类型。

2)CombineInputFormat 核心处理类

2.1)其基本思想:

分片从指定路径下的多个文件构建,不同文件可以放入不同的pool,一个分片只能包含一个pool中的文件,可以包括多个文件的Block。pool其实是针对文件进行了逻辑划分,不同的pool中的文件分别进行分片。分片的逻辑如下文所示。

2.2)分片的逻辑:

如果指定了maxSplitSize(“mapreduce.input.fileinputformat.split.maxsize”),那么在同一个节点上的Blocks合并,一个超过maxSplitSize就生成新分片。如果没有指定,则只汇总本节点BLock,暂不分片。
如果指定了minSizeNode(“mapreduce.input.fileinputformat.split.minsize.per.node”),那么会把1.中处理剩余的Block,进行合并,如果超过minSizeNode,那么全部作为一个分片。否则这些Block与同一机架Rack上的块进行合并。
每个节点上如上同样的方式处理,然后针对整个Rack的所有Block,按照1.方式处理。剩余部分,如果指定了minSizeRack(“mapreduce.input.fileinputformat.split.minsize.per.rack”),并且超过minSizeRack,则全部作为一个分片,否则这些Block保留,等待与所有机架上的剩余Block进行汇总处理。
每个机架上都按照1,2,3方式处理,汇总所有处理剩下的部分,再按照1的逻辑处理。再剩余的,作为一个分片。
以上逻辑我们可以知道:

如果只设置maxSplitSize(如job.getConfiguration().set( “mapreduce.input.fileinputformat.split.maxsize” , “33554432″)),那么基本每个分片大小都需凑满maxSplitSize。

如果maxSplitSize,minSizeNode,minSizeRack三个都没有设置,那是所有输入整合成一个分片!

Hive中可以设置

set mapred.max.split.size=256000000;  #每个Map最大输入大小
set mapred.min.split.size.per.node=100000000; #一个节点上split的至少的大小 
set mapred.min.split.size.per.rack=100000000; #一个交换机下split的至少的大小
set hive.input.format=org.apache.Hadoop.hive.ql.io.CombineHiveInputFormat;  #执行Map前进行小文件合并

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

怒上王者

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值