一、HDFS简介
HDFS(Hadoop distributed File System):Hadoop分布式文件系统。是基于流数据模式访问和处理超大文件的需要而开发的,可以运行于廉价的服务器上。它所具有的高容错,高可靠性,高可扩展性,高获得性,高吞吐率等特征为海量数据提供了不怕故障的存储,为超大数据集的应用带来了很多便利。
简单来说就是把一个超大号文件按一定大小分割并放置在多台服务器上,这样多台服务器同时工作,效率超高,而且安全性也会提高。
二、架构模型
HDFS架构模型为:主从架构。NameNode是主节点。DataNode是从节点。
三、HDFS架构
HDFS主要由四个部分组成,分别为Client,nameNode、DataNode、以及Secondary NameNode组成。
Client(客户端)
1、文件切分:文件上传HDFS的时候,client根据需求将文件切分成一个一个的小数据块(block),然后进行存储。
2、每个小数据块(block)在其他服务器上都有副本,client会与namenode进行通信,获取文件及其副本位置,为以后做打算。
3、与DataNode进行通信,读取或写入数据。
4、client可以管理HDFS,比如启动或关闭。
nameNode(主节点)
NameNode是HDFS的主节点。主要作用有:
1、保存文件和目录的元数据,其中包括:文件的block副本个数、访问和修改时间、访问权限、block大小以及组成文件的block信息。
2、管理fsimage(元数据镜像文件)和edits log(编辑日志)。
注意:fsimage不记录每个block所在的DataNode位置信息。这些信息在每次系统重启的时候从DataNode重建。之后DataNode会周期性的通过心跳来向NameNode报告block信息。DataNode向NameNode注册的时候,NameNode请求DataNode发送block列表信息。
DataNode(从节点)
DataNode是HDFS的从节点,主要就是存储数据块和读写数据块用的:
1、存储实际的数据块
2、执行数据块的读写操作
3、周期性通过心跳向NameNode报告block信息。
4、DataNode每隔3秒向NameNode汇报一次心跳,如果10分钟不汇报(10分钟是确定宕机了,而不是网络延迟等其他原因),NameNode就断定该DataNode宕机,将该DataNode上存储的block副本分发到其他DataNode上。
secondary nameNode
secondary NameNode辅助NameNode工作,主要作用如下:
1、辅助NameNode,分担其工作量。
2、定期合并nameNode中的fsimage(映像文件)和edits log(日志),并推送给nameNode,避免nameNode中的edits log过大。
四、secondary NameNode合并fsimage、edits log流程
1、nameNode检测到edits log达到某个阈值后,会告诉secondary nameNode要进行合并操作了。
2、secondary nameNode收到请求后,会下载nameNode的edits log和fsimage。
3、nameNode收到secondary nameNode下载请求后,会创建一个新的edits log,这时再有操作的话都往这个新的edits log中写,然后把老的edits log和fsimage发送给secondary nameNode。
4、secondary nameNode收到edits log和fsimage后,会按照edits log里记录的操作,一步一步的执行并把数据更新到fsimage文件中。等edits log中执行完了,此时的fsimage已经是最新的了。然后把新的fsimage发送给nameNode。
5、在nameNode收到secondary nameNode发送过来的新的fsimage后。会用新的fsimage代替旧的fsimage,并且删除旧的edits log。
五、HDFS读写流程
写流程
假如现在想将一个文件写入HDFS,流程如下:
1、首先client将文件切分成大小为128M的block,然后调用客户端对象DistributedFileSystem的create方法,DistributedFileSystem跟NameNode通信请求创建一个文件。
2、NameNode收到请求后会进行各种各样的检查,确保要创建的文件不存在,并且客户端有创建文件的权限。如果检查通过,NameNode会在edits log中写入创建文件的操作。否则创建失败,客户端抛出异常。
3、DistributedFileSystem返回一个FSDataOutputStream对象给客户端用来写数据。FSDataOutputStream封装了一个DFSOoutputStream用来跟DataNode和NameNode通信。
4、FSDataOutputStream将block块切分成许多64k大小的小数据包,并将这些小数据包写入到内部队列中(数据队列中)。
5、DataStream会读取队列内容,并请求NameNode返回一个DataNode列表来存储当前的block副本。
6、列表中的DataNode会形成管线,DataStream将数据包发送给第一个DataNode,然后第一个发给第二个,第二个发给第三个。
7、DFSOoutputStream除了维护一个数据队列之外,还维护了一个确认队列(ack队列),ack队列中的数据包是管线中第一台DataNode收到数据包后会第一时间复制一份到ack队列。
8、当一个数据包在管线中所有DataNode写入完成,就从ack队列中移除该数据包,表示该数据包已经成功写入所有的管线的DataNode中。
9、如果在数据写入期间,管线中的DataNode发生故障,则执行如下操作:
a、关闭管线,将ack队列中的所有数据包都添加会数据队列的最前端,确保故障节点下游的DataNode不会丢失任何一个数据包。
b、将管线中正常的DataNode组成一个新的管线,为新管线指定一个新的标志并将该标志发送给NameNode,以便故障DataNode在恢复后可以删除存储的部分数据。
c、将数据队列中的数据包继续写入新管线中。
d、在有后续的数据包则正常处理。
10、当客户端完成数据的传输,调用数据流的close()方法。该方法将数据队列中剩余数据包写入到管线中,并等待确认。
11、客户端收到所有DataNode的确认后,通知NameNode文件写完了。
12、NameNode已经知道文件有哪些块组成,在等待数据块完成最小量复制后,返回成功。
读流程(简单描述)
1、首先客户端会通过自身的对象向NameNode发送通知,请求读取文件。
2、NameNode返回给客户端该文件的block副本存储在哪些DataNode上,并且这些DataNode根据他们与客户端的距离排序。
3、客户端的对象选择离自己最近的DataNode开始读取文件。
4、如果离自己最近的DataNode发生故障,则读第二近的。并记录发生故障的DataNode,下次再有要读该DataNode的时候,直接跳过。
5、读取完毕
这个设计一个重点是:namenode告知客户端每个block中最佳的datanode,并让客户端直接连到datanode检索数据。由于数据流分散在集群中的所有datanode,这样可以使HDFS可扩展到大量的并发客户端。同时,namenode只需要响应block位置的请求,无需响应数据请求,否则namenode会成为瓶颈
六、副本放置策略
第一个副本:放置在上传文件的DataNode;如果是集群外提交,则随机挑选一台磁盘不太满,CPU不太忙的节点。
第二个副本:放置在于第一个副本不同的 机架的节点上。
第三个副本:与第二个副本相同机架的节点。
更多副本:随机节点