在上一章中,我们了解了HDFS的设计思想,从而引出了一些相关概念,比如块、名称节点(Namenode)、数据节点(Datanode)、还有SecondaryNamenode等等。在这一章,我们从HDFS的整体结构上再来全面了解一下。
HDFS 采用的是master/slaves这种主从的结构模型来管理数据,这种结构模型主要由四个部分组成,分别是Client(客户端)、Namenode(名称节点)、Datanode(数据节点)和SecondaryNameNode(第二节点,上面的图解中没有涉及到,下面会讲解)。真正的一个HDFS集群包括一个Namenode和若干数目的Datanode。Namenode是一个中心服务器,负责管理文件系统的命名空间 (Namespace )及客户端对文件的访问。集群中的Datanode一般是一个节点运行一个DataNode进程,负责管理客户端的读写请求,在Namenode的统一调度下进行数据块的创建、删除和复制等操作。数据块实际上都是保存在Datanode本地的Linux文件系统中的。每个Datanode会定期的向Namenode发送数据,报告自己的状态(我们称之为心跳机制)。没有按时发送心跳信息的Datanode会被Namenode标记为“宕机”,不会再给他分配任何I/O请求。
用户在使用Client进行I/O操作时,仍然可以像使用普通文件系统那样,使用文件名去存储和访问文件,只不过,在HDFS内部,一个文件会被切分成若干个数据块,然后被分布存储在若干个Datanode上。
比如,用户在Client上需要访问一个文件时,HDFS的实际工作流程如此:客户端先把文件名发送给Namenode,Namenode根据文件名找到对应的数据块信息及其每个数据块所在的Datanode位置,然后把这些信息发送给客户端。之后,客户端就直接与这些Datanode进行通信,来获取数据(这个过程,Namenode并不参与数据块的传输)。这种设计方式,实现了并发访问,大大提高了数据的访问速度。
HDFS集群中只有唯一的一个Namenode,负责所有元数据的管理工作。这种方式保证了Datanode不会脱离Namenode的控制,同时,用户数据也永远不会经过Namenode,大大减轻了Namenode的工作负担,使之更方便管理工作。通常在部署集群中,我们要选择一台性能较好的机器来作为Namenode。当然,一台机器上也可以运行多个Datanode,甚至Namenode和Datanode也可以在一台机器上,只不过实际部署中,通常不会这么做的哦。
严格意义上,HDFS集群上是没有客户端这一部分的,它只是提供了用户操作HDFS的程序接口。HDFS提供了各种各样的客户端接口,比如命令行接口、Java API, Thrift接口、C语言库、用户空间文件系统〔Filesystem in Userspace,FUSE)等。这样,用户就可以有选择的使用客户端程序来操纵HDFS进行浏览、读取和写入等操作了。
客户端程序可以在集群外的任意一台机器上,也可以在集群中的一个节点上。只要客户端能拥有Namenode的ip地址以及端口号信息。
Namenode是集群主从(master/slaves)结构模型中的唯一一个管理者(master),它负责维护HDFS文件系统的命名空间,以及管理数据块位置信息,也管理着客户端的读写操作。
命名空间(Namespace)的管理:命名空间指的就是文件系统树及整棵树内的所有文件和目录的元数据,每个Namenode只能管理唯一的一命名空间。HDFS暂不支持软链接和硬连接。Namenode会在内存里维护文件系统的元数据,同时还使用fsimage和editlog两个文件来辅助管理元数据,并持久化到本地磁盘上。
fsimage:命名空间镜像文件,它是文件系统元数据的一个完整的永久检查点,内部维护的是最近一次检查点的文件系统树和整棵树内部的所有文件和目录的元数据,如修改时间,访问时间,访问权限,副本数据,块大小,文件的块列表信息等等。
使用XML格式查看fsimage文件:
$ hdfs oiv -i 【fsimage_xxxxxxxxxxxx】 -o 【目标文件路径】 -p XML
如:$ hdfs oiv -i fsimage_0000000000000000052 -o ~/fs52.xml -p XMLeditlog:编辑日志文件,当hdfs文件系统发生打开、关闭、创建、删除、重命名等操作产生的信息除了在保存在内存中外,还会持久化到编辑日志文件。比如上传一个文件后,日志文件里记录的有这次事务的txid,文件的inodeid,数据块的副本数,数据块的id,数据块大小,访问时间,修改时间等
查看editlog文件的方式:
$ hdfs oev -i 【edits_inprogress_xxxxxxxxxxxxxx】 -o 【目标文件路径】
如: $ hdfs oev -i edits_inprogress_000000000000000003 -o ~/ed3.xml
Namenode在内存中,也记录着每个文件的各个块所在的数据节点的位置信息(数据块-Datanode映射信息),但是并不持久保存位置信息,因为这些信息会在文件系统启动时动态的重建这些信息(心跳机制,blockreport)。
当然,Namenode也管理着客户端对文件的访问等操作,比如客户端想要访问一个文件,得需要通过Namenode的检查,比如权限检查,文件是否存在,及其数据块的Datanode列表信息等。
Datanode是HDFS主从结构模式中的工作者,在HDFS集群上,有若干个Datanode。Datanode负责数据块的存储和读取(会根据客户端或者Namenode的调度来进行数据的存储和检索),数据块会存储在节点的本地Linux文件系统中(包括block和block.meta)。Datanode会定期向Namenode发送自己所存储的块的列表(心跳机制,blockreport)。
HDFS集群中,有一个Namenode和若干个Datanode,这些节点通常分布在不同的机架(Rack)上,每个机架上可存放8~64个Datanode。一个机架上的不同节点使用同一个网络连接进行互通,机架之间使用另一级网络或交换机互联。
SecondaryNamenode,是HDFS集群中的重要组成部分,它可以辅助Namenode进行fsimage和editlog的合并工作,减小editlog文件大小,以便缩短下次Namenode的重启时间,能尽快退出安全模式。
两个文件的合并周期,称之为检查点机制(checkpoint),是可以通过hdfs-default.xml配置文件进行修改的:
dfs.namenode.checkpoint.period
3600
两次检查点间隔的秒数,默认是1个小时
dfs.namenode.checkpoint.txns
1000000
txid执行的次数达到100w次,也执行checkpoint
dfs.namenode.checkpoint.check.period
60
60秒一检查txid的执行次数
我们再来看看SecondaryName是如何创建检查点的?
创建检查点(参考图片)的步骤如下:
1)、SecondaryNamenode请求Namenode停止使用正在编辑的editlog文件,Namenode会创建新的editlog文件(小了吧),同时更新seed_txid文件。
2)、SecondaryNamenode通过HTTP协议获取Namenode上的fsimage和editlog文件。
3)、SecondaryNamenode将fsimage读进内存当中,并逐步分析editlog文件里的数据,进行合并操作,然后写入新文件fsimage_x.ckpt文件中。
4)、SecondaryNamenode将新文件fsimage_x.ckpt通过HTTP协议发送回Namenode。
5)、Namenode再进行更名操作。
这个过程清晰的解释了SecondaryNamenode和Namenode要有相近的内存需求才行,两者都会将fsimage加载到内存里,因此,在一些大型集群中,SecondaryNamenode通常都要运行在一台专用机器上。
我们应该还可以想到,在创建检查点的过程中,Namenode上的新的editlog可能已经记录了一些新的操作日志。如果在这个过程中,Namenode发生了故障,那么就会丢失部分元数据,在HDFS的设计中,也并不支持把系统直接切换到SecondaryNamenode,因此从这个角度来讲,SecondaryNamenode只是起到了名称节点的“检查点”作用,并不能起到“热备份”作用。
Namenode启动时,首先要加载fsimage文件到内存,并逐条执行editlog文件里的事务操作,在这个期间一但在内存中成功建立文件系统元数据的映像,就会新创建一个fsimage文件(该操作不需要SecondaryNamenode)和一个空的editlog文件。在这个过程中,namenode是运行在安全模式下的,Namenode的文件系统对于客户端来说是只读的,文件修改操作如写,删除,重命名等均会失败。
Namenode不会存储数据块的位置信息,因此Namenode在启动后,还会等待接受Datanode的blockreport(数据块的状态报告)。严格来说,只有接受到状态报告后,客户端的读操作才能成功完成。
PS:启动一个刚刚格式化完的集群时,HDFS还没有任何操作呢,因此Namenode不会进入安全模式。
查看namenode是否处于安全模式:
[michael@master current]$ hdfs dfsadmin -safemode get
Safe mode is ON
管理员可以随时让Namenode进入或离开安全模式,这项功能在维护和升级集群时非常关键
[michael@master current]$ hdfs dfsadmin -safemode enter
Safe mode is ON
[michael@master current]$ hdfs dfsadmin -safemode leave
Safe mode is OFF
将下面的属性的值设置为大于1,将永远不会离开安全模式
dfs.namenode.safemode.threshold-pct
0.999f
有时,在安全模式下,用户想要执行某条命令,特别是在脚本中,此时可以先让安全模式进入等待状态
[michael@master current]$ hdfs dfsadmin -safemode wait
# command to read or write a file
所有的HDFS通信协议都是构建在TCP / IP协议基础之上的。客户端通过可配置的TCP端口主动向Namenode发送TCP请求建立连接。它将使用客户端协议与NameNode进行通信。Datanode使用Datanode协议与Namenode通信。客户端和Datanode使用远程过程调用(RPC)进行通信。NameNode永远不会主动启动任何RPC,它只响应DataNodes或客户端发出的RPC请求。