一、体系架构
HDFS 采用的是master/slaves主从结构模型来管理数据,这种结构模型主要由四个部分组成:Client(客户端)、Namenode(名称节点)、Datanode(数据节点)和SecondaryNamenode(第二名称节点,辅助Namenode)。一个真正的HDFS集群包括一个Namenode和若干数目的Datanode。Namenode是一个中心服务器,负责管理文件系统的命名空间 (Namespace )及客户端对文件的访问。集群中的Datanode一般是一个节点运行一个Datanode进程,负责管理客户端的读写请求,在Namenode的统一调度下进行数据块的创建、删除和复制等操作。数据块实际上都是保存在Datanode本地文件系统中的。每个Datanode会定期的向Namenode发送数据信息,报告自己的状态(心跳机制)。没有按时发送心跳信息的Datanode会被Namenode标记为“宕机”,“宕机”的Datanode不会被分配I/O任务。
用户在Client上需要访问一个文件时,HDFS的实际工作流程:客户端先把文件名发送给Namenode,Namenode根据文件名找到对应的数据块信息及其每个数据块所在的Datanode位置,然后把这些信息发送给客户端。之后,客户端就直接与这些Datanode进行通信,来获取数据。这种设计方式,实现了并发访问,大大提高了数据的访问速度,最小化寻址开销就显得尤为重要。
HDFS集群中只有唯一的一个Namenode,负责所有元数据的管理工作。这种方式保证了Datanode不会脱离Namenode的控制,同时,用户数据也永远不会经过Namenode,大大减轻了Namenode的工作负担,使之更方便管理工作。通常在部署集群中,我们要选择一台性能较好的机器来作为Namenode。当然,一台机器上也可以运行多个Datanode,甚至Namenode和Datanode也可以在一台机器上,但是在实际运用中,为了给Namenode尽可能多的内存,不会有将Namenode和Datanode放在同一节点的情况。
深层解析
Client
HDFS提供了多种客户端接口供应程序以及用户使用,包括命令行接口、浏览器接口以及代码API接口。用户通过这些接口可以很方便地使用HDFS,而不需要考虑HDFS的实现细节。HDFS客户端接口的实现都是建立在DFSClient类的基础上。
Namenode
- 命名空间(namespace)管理:它维护着文件系统树(filesystem tree)以及文件树中所有的文件和文件夹的元数据(metadata)。管理这些信息的文件有两个,分别是Namespace 镜像文件(fsimage)和操作日志文件(edit log)。
fsimage:命名空间镜像文件,它是文件系统元数据的一个完整的永久检查点,内部维护的是最近一次检查点的文件系统树和整棵树内部的所有文件和目录的元数据,如修改时间,访问时间,访问权限,副本数据,块大小,文件的块列表信息等等。
editlog:编辑日志文件,当hdfs文件系统发生打开、关闭、创建、删除、重命名等操作产生的信息除了在保存在内存中外,还会持久化到编辑日志文件。比如上传一个文件后,日志文件里记录的有这次事务的txid,文件的inodeid,数据块的副本数,数据块的id,数据块大小,访问时间,修改时间等
- 文件Block管理:Namenode记录着每个文件中各个块所在的数据节点的位置信息(元数据信息),从NameNode中你可以获得每个文件的每个块所在的DataNode。但是他并不持久化存储这些信息,确定block到Datanode的映射(注意:心跳机制:status和blockreport;默认3秒一次)
元数据信息主要为:
"文件名 -> 数据块"映射
"数据块 -> Datanode列表"映射
其中,"文件名 -> 数据块"保存在磁盘上进行持久化存储,需要注意的是NameNode上不保存"数据块 -> DataNode列表"映射,该列表是通过心跳机制建立起来的。Namenode执行文件系统的名称空间(namespace)操作,例如打开、关闭、重命名文件和目录,同时决定文件数据块到具体Datanode节点的映射。
Datanode
Datanode是HDFS主从结构模式中的工作者,在HDFS集群上,有若干个Datanode。
Datanode负责数据块的存储和读取(会根据客户端或者Namenode的调度来进行数据的存储和检索),数据块会存储在节点的本地Linux文件系统中(包括block和block.meta)。
Datanode会定期向Namenode发送自己所存储的块的列表(心跳机制,blockreport)。
数据块
存储在hdfs中的最小单位
默认大小:128M
原因:
为了最小化寻址开销,一般寻址时间为10ms,传输速率为100MB/s
为了寻址时间占传输时间的1%,所以。。。。。
修改块大小
<property>
<!--修改块大小 默认128M-->
<name>dfs.blocksize</name>
<value>134217728</value>
</property>
<property>
<!--设置最小块大小的值-->
<name>dfs.namenode.fs-limits.min-block-size</name>
<value>1048576</value>
</property>
<property>
<!--设置校验和的值 必须能将块大小整除-->
<name>dfs.bytes-per-checksum</name>
<value>512</value>
</property>
SecondaryNamenode
SecondaryNamenode,是HDFS集群中的重要组成部分,它可以辅助Namenode进行fsimage和editlog的合并工作,减小editlog文件大小,以便缩短下次Namenode的重启时间,能尽快退出安全模式。
editlog和fsimage两个文件的合并周期,称之为检查点机制(checkpoint)
fsimage文件是文件系统元数据的持久化检查点,不会在写操作后马上更新,因为fsimage写非常慢。
由于editlog不断增长,在Namenode重启时,会造成长时间Namenode处于安全模式,不可用状态,是非常不符合Hadoop的设计初衷。所以要周期性合并editlog,但是这个工作由Namenode来完成,会占用大量资源,这样就出现了Secondary Namenode,它可以进行image检查点的处理工作。步骤如下:
(1) SecondaryNamenode请求Namenode进行editlog的滚动(即创建一个新的editlog),将新的编辑操作记录到新生成的editlog文件;
(2) 通过http get方式,读取NameNode上的fsimage和edits文件,到SecondaryNamenode上;
(3) 读取fsimage到内存中,即加载fsimage到内存,然后执行edits中所有操作,并生成一个新的fsimage文件(fsimage.ckpt临时文件),即这个检查点被创建;
(4) 通过http post方式,将fsimage.ckpt文件传送到Namenode;
(5) Namenode使用新的fsimage替换原来的fsimage文件(fsimage.ckpt重命名为fsimage),让(1)创建的edits(editlog)替代原来的edits文件;并且更新fsimage文件的检查点时间。
可以通过以下属性对其进行修改:
<property>
<!--两次检查点间隔的秒数 默认是1个小时-->
<name>dfs.namenode.checkpoint.period</name>
<value>3600</value>
</property>
<property>
<!--txid执行的次数 默认达到100w次,也执行checkpoint-->
<name>dfs.namenode.checkpoint.txns</name>
<value>1000000</value>
</property>
<property>
<!--检查txid执行次数的时间间隔 默认60秒一检查-->
<name>dfs.namenode.checkpoint.check.period</name>
<value>60</value>
</property>