HDFS学习——基本概念

HDFS是Hadoop的核心之一,是一个分布式文件系统。所谓分布式文件系统,就是多个节点通过网络形成一个整体系统,它和单机文件系统的最大区别在于,可以存储一个远超单机存储能力的文件。
其存储方式大致就是:把文件分隔成若干个份,存放在不同的节点上,再由一个角色(HDFS中是Namenode)负责记录文件的某一份存放在哪个节点上。当用户想要读取文件的时候,首先会和Namenode交互,获取文件数据的具体存放位置,然后在和对应节点进行交互,从而获取文件数据。

1 HDFS的设计目标

HDFS在设计之初,就已经假设了很多极端情况,并对这些情况作了很好的处理,因此HDFS的可靠性非常好。下面详细介绍:

硬件容易发生故障
HDFS假设硬件发生故障是一个正常事件,HDFS在遇到硬件故障时,会通过备份机制很好的保障数据不丢失,并且还可以对用户屏蔽故障感知

数据量大
HDFS假设运行在HDFS平台上的应用都是具有很大的数据集。因此HDFS可以很好的协调多个节点来存储这些大文件。但是伴随的是,HDFS对于小而多的文件的处理能力不是很好。

简化一致性模型
HDFS认为文件一旦被写入之后,就会被持久化保存,不被修改。这个假设有一定的道理,因为HDFS被设计为存储大文件,因此对于大文件而言即使有错误,相对于巨大的总体数据而言也会显得不足以对最终结果产生影响;另外对大文件进行修改,本身就是一件困难的事情,首先去定位目标数据所在位置,都需要费一番功夫,因此HDFS干脆不支持对文件进行修改。

2 HDFS基本概念

HDFS中比较主要的概念有:Namenode,Block,Datanode

HDFS是一个主从架构,Namenode就是其Master节点,用于管理整个文件系统的命名空间,并且负责与客户端进行交互,返回文件中具体数据的存放位置;

Datanode通常集群中的一个个节点,负责管理分该节点上的所有Block,并且通过TCP协议定时想Namenode发送心跳来报告自己的状态及信息,以便于Namenode能够即使知道这个Datanode是否还正常,存储的数据量是否已经达到阈值等等。

Block是用于存储文件真实数据的逻辑单位,由于HDFS被设计成善于存储大文件,因此相比于普通的文件系统而言,它的一个Block的大小是远大于后者的,它的默认大小是128MB(这事Hadoop2.x的默认值),不仅如此,为了应对硬件可能出现的故障,默认情况下,HDFS默认为每个Block,创建三个副本。

3 HDFS的基本架构图

HDFS架构如图所示:

HDFS学习——基本概念

从图中可以看出:

  • 一个HDFS集群中,Namenode只有一个,而Datanode可以有多个
  • Namenode里面仅仅存储元数据信息,并不存放文件的真实数据信息;Datanode中的Block负责存储文件的实际数据;
  • Client在向HDFS中读写数据时,不仅需要和Namenode交互,还需要和Datanode交互。以读操作为例,Client会首先和Namenode交互,Namenode会根据自己存储的元数据信息,确定Client要读的文件内容存放在哪个Block中,这些Block都在哪些节点上,然后把这些信息返回给Client,Client根据这些信息去对应节点上与Datanode进行交互,从而获取到文件数据。

4 HDFS为什么不适合存储海量小文件

HDFS默认的Block大小为128M,因此在HDFS中所谓的小文件,就是大小远小于128M的文件就被称之为小文件。 在HDFS世界里,不管这个文件有多小,只要它存放在HDFS中,都会至少占用一个Block,尽管实际上占用的存储空间是文件的大小。这是因为在Namenode看来,一个文件至少需要一个Block,它是根据这个Block的id来确定文件的实际存放位置。

HDFS不适合存储海量小文件的原因在于,海量的小文件对于Datanode没有什么影响,但是对Namenode对造成巨大的负担。Namenode会为每个存储在集群中的文件创建一个对象,这个对象中包含文件的路径信息、文件存放在那些Block中(以BlockID表示)、文件名等一系列信息,据资料介绍,Namenode中用于代表一个文件的对象大小约150字节。因此当HDFS中存储的文件越多,那么Namenode中表示文件的对象就会越多,相应的,Namenode中所需要的内存就越大。据资料估算,如果HDFS中存放10亿个小文件(每个文件都小于128M),那么Namenode为记录这些存储文件需要的内存大约为300GB,这还不算其他进程占用的内存,因此这对于单机而言,内存过大。当Namenode所需要内存过大时,会带来如下影响:

可以看这篇博文:Hadoop解决小文件存储思路和增加namenode内存

  • Namenode是一个Java进程,它需要过大内存,这意味着JVM需要为此配置很大的容量的heap,heap过大,那么GC的时间就会非常长,这不仅仅影响JVM的效率,严重的时候可能会导致JVM崩掉
  • 那么当Client要读取一个文件的时候,Namenode会检索自己的元数据信息,找到这个目标文件对象,Namenode所需内存很大,就意味着,Namenode中存储的文件对象很多,检索一次也会很慢;另外,当Namenode重启的时候,需要从磁盘中读取每个文件的元数据信息,存储的文件很多很多时,那么读取所花费的时间也就很长,Namenode重启速度就会很慢;
  • Namenode会不断跟踪每一个Block,这是通过与Datanode通信,Datanode发送心跳来跟踪的,因为有10亿个小文件,那么就有10亿个Block,再加上备份,可能需要跟踪10亿个Block,那么Datanode发送心跳时占用的过多的带宽,导致出现网络问题。