Hadoop(三)HDFS的存储原理


原文地址:http://www.cnblogs.com/zhangyinhua/p/7681059.html
注:本系列为Hadoop学习笔记,非原创

一、HDFS读取过程

HDFS读取操作.png

(1)客户端通过调用FileSytem对象的open()来读取希望打开的文件。对于HDFS来说,这个对象是分布式文件系统的实例;
(2)DistributedFileSytem通过RPC来调用Namenode,以确定文件的开头部分的块位置。对于每一块,Namenode返回该块副本的Datanode地址。此外,这些Datanode会根据它们与client的距离来排序(根据网络集群的拓扑)。如果该client本身就是一个Datanode,便从本地Datanode读取。DistributedFileSytem返回一个FSDataInputStream对象给client读取数据,FSDataInputStream转而包装成一个DFSInpuStream对象;
(3)接着client对于这个输入流调用read()。存储着文件开头部分的块的数据节点的地址DFSInputStream随即与这些块最近的Datanode相连接;
(4)通过在数据流中反复调用read(),数据会从Datanode返回到client;
(5)达到块的末端时,DFSInputStream会关闭与Datanode间的联系,然后为下一个块找到最佳的Datanode。client端只需要读取一个连续的流,这些对于client都是透明的;
(6)在读取的时候,如果client和Datanode通讯时遇到一个错误,那么它就会去尝试对这个块来说下一个最近的块。它也会记住那个故障节点的Datanode,以保证之后不会进行徒劳无益的尝试,client也会确认Datanode发送来得数据校验和。如果发现一个损失的块,它就会在client试图从别的Datanode中读取一个块的副本之前报告给Namenode;
(7)这个设计的一个重点是,client直接联系Datanode去检索数据,并被Namenode指引到块中最好的Datanode。因为数据流在此集群中是在所有Datanode酚酸进行的。所以这种设计能使HDFS可扩展到最大的并发client数量。同时,Namenode只不过提供块的位置请求(存储在内存,十分高效),不是提供数据。否则如果客户端数量增长,Namenode就会快速成为一个“瓶颈”。

二、HDFS的写入过程

HDFS写入操作.png

(1)客户端通过DistributedFileSytem中调用create()来创建文件;
(2)DistributedFileSytem使用RPC去调用Namenode,在文件系统的命名空间创造一个新的文件,没有快与之相联系。
1、Namenode执行不同的检查(这个文件是否存在,有无权限去写入 ,能否存储下这个文件)以确保这个文件不会已经存在,并且在client有创造文件的适当许可;
2、如果检查通过,Namenode就会生成一个新的文件记录。否则文件创建失败并向client抛出一个IOException异常;
3、分布式文件系统返回一个文件系统数据输出流让client开始写入数据。就像读取时间一样,文件系统数据输出流控制一个DFSOutputStream,负责Datanode和Namenode之间的通信;
(3)在client写入数据时,DFSOutputStream将它分成一个个的包,写入内部的队列,成为数据队列。数据队列随数据流流动,数据流的责任是根据适合的Datanode的列表要求这些节点为副本分配新的块(这个数据节点的列表形成一个管线--假定副本数为3,所以有3个节点在管线中);
(4)数据流将包分分流给管线中第一个Datanode,这个节点会存储包并且发送给管线中第二个Datanode。同样,第二个Datanode存储包并发送给第三个数据节点;
(5)DFSOutputStream也有一个内部的包队列来等待Datanode收到确认,成为确认队列。一个包只有在管线中所有的节点确认后才会被移除确认队列。
1、如果有数据写入期间,Datanode发生故障,那么首先管线被关闭,确认队列中的任何包都会被添加回数据队列前面,以确保故障节点下游 的Datanode不会漏掉任何一个包;
2、为存储在另一正常的Datanode的当前数据块定制一个新的标识,并将该标识传给Namenode,一边故障节点Datanode恢复后可以删除存储的部分数据块;
3、从管线中算出故障数据节点并且把余下的数据块写入管线中两个正常的Datanode。Namenode注意到块副本量不足时,会从另一个节点上创造一个新的副本;
(6)client完成数据写入后,就会在流中调用close();
(7)在向Namenode节点发送完信息前,此方法会将余下所欲包放入Datanode管线并等待确认;
1、Namenode已经知道文件 是由哪些块组成(通过DataStreamer询问块分配),所以它只需要在成功前等待块进行最小量的复制;
(8)副本的布局:Hadoop默认布局策略是在client的节点上放第1个副本(如果客户端运行在运行在集群之外,就随机选择一个节点,不过系统会避免挑选存储太满或者太忙的节点);第2个副本放在与第1个副本不同且随机另外选择的机架的节点上(离架),第3个副本与第2个副本放在同样的机架,且随机选择另一个节点。其他复本放在集群中随机的节点上,不过系统会尽量避免相同的机架放太多复本。

三、实例说明HDFS的读写过程

HDFS写入过程(实例).png

前提:
有一个文件FileA,100M大小。Client将FileA写入到HDFS上。HDFS按默认配置。HDFS分布在三个机架上Rack1,Rack2,Rack3。
步骤:
(1)Client将FileA按64M分块。分成两块,block1和Block2;
(2)Client向nameNode发送写数据请求,如图蓝色虚线①------>。
(3) NameNode节点,记录block信息。并返回可用的DataNode,如粉色虚线②--------->。
Block1: host2,host1,host3
Block2: host7,host8,host4
原理:
NameNode具有RackAware机架感知功能,这个可以配置。若client为DataNode节点,那存储block时,规则为:副本1,同client的节点上;副本2,不同机架节点上;副本3,同第二个副本机架的另一个节点上;其他副本随机挑选。若client不为DataNode节点,那存储block时,规则为:副本1,随机选择一个节点上;副本2,不同副本1,机架上;副本3,同副本2相同的另一个节点上;其他副本随机挑选。
(4)client向DataNode发送block1;发送过程是以流式写入。
流式写入过程:
(1)将64M的block1按64k的package划分;
(2)然后将第一个package发送给host2;
(3)host2接收完后,将第一个package发送给host1,同时client想host2发送第二个package;
(4)host1接收完第一个package后,发送给host3,同时接收host2发来的第二个package。
(5)以此类推,如图红线实线所示,直到将block1发送完毕。
(6)host2,host1,host3向NameNode,host2向Client发送通知,说“消息发送完了”。如图粉红颜色实线所示。
(7)client收到host2发来的消息后,向namenode发送消息,说我写完了。这样就真完成了。如图黄色粗实线
(8)发送完block1后,再向host7,host8,host4发送block2,如图蓝色实线所示。
(9)发送完block2后,host7,host8,host4向NameNode,host7向Client发送通知,如图浅绿色实线所示。
(10)client向NameNode发送消息,说我写完了,如图黄色粗实线。。。这样就完毕了。
分析:
通过写过程,我们可以了解到:
(1)写1T文件,我们需要3T的存储,3T的网络流量贷款。
(2)在执行读或写的过程中,NameNode和DataNode通过HeartBeat进行保存通信,确定DataNode活着。如果发现DataNode死掉了,就将死掉的DataNode上的数据,放到其他节点去。读取时,要读其他节点去。
(3)挂掉一个节点,没关系,还有其他节点可以备份;甚至,挂掉某一个机架,也没关系;其他机架上,也有备份。

四、实例说明HDFS读取过程

HDFS读取操作.png

读操作就简单一些了,如图所示,client要从datanode上,读取FileA。而FileA由block1和block2组成。 那么,读操作流程为:
(1)client向namenode发送读请求。
(2)namenode查看Metadata信息,返回fileA的block的位置。
block1:host2,host1,host3
block2:host7,host8,host4
(3)block的位置是有先后顺序的,先读block1,再读block2。而且block1去host2上读取;然后block2,去host7上读取;
(4)上面例子中,client位于机架外,那么如果client位于机架内某个DataNode上,例如,client是host6。那么读取的时候,遵循的规律是:优选读取本机架上的数据。

你可能感兴趣的:(Hadoop(三)HDFS的存储原理)