- MapReduce 2.0源码分析与编程实战
- 王晓华
- 711字
- 2020-06-26 13:50:11
2.2 HDFS数据存取流程分析
HDFS将文件架构分成两大部分,分别是NameNode与DataNode。文件通过NameNode在系统中进行分配,DataNode负责对文件进行存储,并将本节点信息反馈给NameNode,从而完成文件存储的分配以及存储状态的获取。
目前读者所看到的是一个比较系统的概念,对HDFS中具体数据的分析并不能只进行简单的理论分析,而要对具体流程进行详细的叙述。
2.2.1 HDFS数据存储位置与复制详解
HDFS 是一种高度分布的多层次结构布局。典型的 HDFS 集群是将数百个服务器同时部署在同一个集群之中,并且可以同时被来自同一或者不同地点的多个客户机访问。HDFS数据存储的目标有两个,即最大化数据可靠性与可用性以及最大化利用网络带宽资源。为了实现这两个目的,仅仅在多台机器上进行单一存储是不够的,不能预防硬件设备失误带来的损失。因此,采用多副本存储复制,在多个节点之间重复分布存储数据副本,保证了即使有一个存储所需数据硬件设备损坏,也能够安全合理地获得所需要的数据。同时为扩大资源的利用带宽,对节点的选择则需要进行专门的研究与设计。
那么,NameNode如何选择具体的DataNode来存储数据,并能够充分利用现有带宽呢?在回答这个问题之前,首先需要对节点和带宽作出HDFS中的定义。
在通过宽带网络进行数据交换与处理过程中,把数据传输速度作为节点之间的衡量标准是自然并且可行的。但是问题在于,在实际工作中,带宽或者说传输速率的影响因素非常多,例如网络的稳定性、其他数据的传输带宽占用以及交换机的负载等等都能够对某个时间点的带宽起到决定性的作用。因此,并不能简单地把传输速度作为节点距离的衡量标准。
为了解决通过测量带宽不能够获得一个长期、准确、稳定的速率的问题,HDFS 采用了另一个简单的方法对带宽进行衡量。假设客户端即数据的调用端为数据的获取点,根据数据存放的相对位置来衡量距离值。设定见下,距离值依次增加。
● 同一节点上的存储数据。
● 同一机架上不同节点上的存储数据。
● 同一数据中心不同机架上的存储数据。
● 不同数据中心的节点。
定义的这四个位置距离值依次增加,标志以此作为衡量距离,其距离位置加长。可以假设数据中心某一个客户端Client需要获取相关数据Data,那么根据不同Data存储的位置可以获得如下假设。
● Client同一节点上不同存储Data距离为0。
● Client同一机架上不同节点上的存储数据Data距离为3。
● Client同一数据中心不同机架上的存储数据Data距离为6。
● Client不同数据中心的节点Data距离为9。
可以看到,HDFS 通过定义客户端与数据的相对位置来获取定义后的距离值,也可以较为方便直观地获取距离的衡量标准,从而获得更快捷的数据输入。
在确定数据距离值后,HDFS 中 NameNode 节点即可根据定义的距离值对需要存储的数据进行切割和存储。同时,为了维护数据的稳定性与预防灾难,还需要将数据进行副本的备份操作。
副本存放位置的选取是需要进行考虑和评价的。复制操作要对带宽及传输速率进行衡量,衡量的标准也是上文定义的距离值。如果想要求最高的网络速度,那么将所有数据都存放在同一节点上是最为合适的,但是此种存放方法非常危险。如果你无法正确估量和测试硬件的稳定状态,一旦灾难发生,则可能无法避免数据损失。
如果换另一种极端的方法考虑,将数据存放在不同数据中心不同节点中,那么,不同数据中心不同节点同时出现故障的可能性是非常低的。但是,由于客户端有可能需要对多个节点中的数据进行读写操作,因此,此种存放方法会在传输速率上大打折扣。
小提示:对副本的复制操作可以自行制定数目,如果数据过于庞大而安全性不是那么重要,例如访问日志文件等,可以减少复制的副本数目,或者关闭HDFS复制而采用硬盘Raid模式。
HDFS数据存放策略就是采用同节点与同机架并行的存储模式,制作成三个副本存储在运行客户端的当前节点上存放第一个副本,第二个副本存放在与第一个副本不同的机架的节点上,第三个副本放置的位置与第二个副本在同一个机架上而非同一个节点,如图2-2所示。
图2-2 节点存储行为
2.2.2 HDFS 输入流程分析
在HDFS中,数据之间的交互是通过宽带网络进行的,而对于具体的交互程序,又分为输入与输出过程,输入过程如图2-3所示。
图2-3 HDFS数据存储过程
以上是输入过程的一个图示,下面对具体过程作进一步的分析。
(1)客户端或者用户通过调用 FileSystem 对象的 open()方法打开需要读取的文件,从而创建一个HDFS的读取对象实例。
(2)FileSystem通过远程协议调用NameNode获取文件处于前端的几个Block的位置。并根据上文定义的客户端与DataNode距离值进行排序。
(3)NameNode将与客户端对应最近的那个文件的起始Block地址返回给客户端,客户端根据地址创建一个FSDataInputStream开始对数据进行读取。
(4)FSDataInputStream根据返回的Block地址,连接到最近的DataNode上对数据Block开始读取。通过反复调用read()方法,以流的方式从DataNode中读取数据。
(5)当读到Block结尾的时候,FSDataInputStream会关闭当前DataNode的链接,然后查找能够读取下一个Block的最好的DataNode。这些操作对客户端是透明的,客户端感觉到的是连续的流,也就是说读取的时候就开始查找下一个块所在的地址。
(6)读取完成,调用close()方法,关闭FSDataInputStream。
以上就是HDFS对数据进行读取的整个流程。
客户端在获取数据的过程中,只需要访问NameNode一次获得起始位置的Block,即可开始对数据进行持续而直接的读取。这样做的好处是HDFS能够服务大量的客户端。不同的数据传输是通过集群中不同的DataNode与客户端直接连接而成的。NameNode只需要提供一次查询基本信息的操作即可,而不需要提供任何数据服务工作,极大地提高了 HDFS 的整体性能。
当客户端的读取操作发生错误时,客户端会向 NameNode 报告错误,并请求 NameNode排除错误的DataNode后重新根据距离值排序,从而获得一个新的DataNode的读取路径。如果所有的DataNode都报告读取失败,那么任务读取失败。
小提示:NameNode 中存放的基本信息有个特定称谓被叫做“元数据”。一般包含数据类型、大小、格式以及对象的存放形式等。
2.2.3 HDFS输出流程分析
与HDFS的输入类似,HDFS的输出也需要通过NameNode获得DataNode的基本信息,从而执行对应的输出过程,具体过程如图2-4所示。
图2-4 HDFS数据输出过程
输出流程也分为若干个步骤,下面我们对具体过程作进一步的分析。
(1)首先客户端通过调用create方法来向FileSystem请求创建文件。
(2)FileSystem向NameNode发出创建请求后,NameNode进行了若干步检查来确定需要创建的文件或目录是否已经存在,并且确认提出请求的客户端是否有权限创建相应的文件或目录。
(3)如果检查通过, NameNode 会保存创建文件的请求并向客户端返回一个FSDataOutputStream 地址供客户端写出数据。而如果在 NameNode 中的检查没通过,则客户端会立刻收到一个IOException,表示文件创建请求失败,任务被停止。
(4)客户端在收到FSDataOutputStream后调用write方法对数据进行写出操作。客户端会将数据分成若干个Block,然后在NameNode分配的FSDataOutputStream中找到具有最近距离值的那个DataNode进行数据的写出。
(5)对数据进行备份操作在数据被写到第一个DataNode完毕后立即开始,如果默认将数据进行三次副本备份的话,那么首先将数据写到第一个DataNode中。此后由第一个DataNode将数据复制到第二个DataNode中,第二个DataNode会将数据写到第三个DataNode。
(6)全部数据写出结束后,FSDataOutputStream调用close方法,关闭写出流。
对于写出操作过程中出现的问题, FSDataOutputStream 并不会立即关闭。客户端向NameNode报告错误信息,并直接向提供备份的DataNode中写入数据。备份DataNode被升级为首选DataNode。重新进行步骤(5)的操作。NameNode对错误的DataNode进行标记以便在后续对其进行处理。
小提示:尽管在写入数据的时候可能会有多个节点出现故障,但是只要默认的一个节点(dfs.replication.min)被写入了,那么这个操作就会完成。因为数据将自动在集群间复制,直到复制达成定义好的次数。