HDFS读写数据流程

HDFS读写数据流程

标签(空格分隔): Apache Hadoop


HDFS是hadoop重要的组件之一,对其进行数据的读写是很常见的操作,然而真的了解其读写过程吗?

前言

HDFS – Hadoop Distributed File System,是hadoop的存储层,它参照google的GFS思想实现。

它以master-slave工作。NameNode作为master daemon,工作在master node上,DataNode作为slave daemon,工作在slave node上。master 之间在 HDFS 2.X.X 版本实现HA 高可用。

一,写HDFS

1. 流程图

image.png-224.3kB

2. 重要概念

HDFS一个文件由多个block构成。或者说一个文件会被切分成按照HDFS block 大小的多个块去存储。

HDFS在进行block读写的时候是以packet(默认每个packet为64K)为单位进行的。

每一个packet由若干个chunk(默认512Byte)组成。Chunk是进行数据校验的基本单位,对每一个chunk生成一个校验和(默认4Byte)并将校验和进行存储。

在写入一个block的时候,数据传输的基本单位是packet,每个packet由若干个chunk组成。

3. 过程步骤

1) HDFS client发送一个create请求给DistributedFileSystem API

2)DistributedFileSystem 使用一个RPC请求,通知NameNode在其命名空间创建一个新文件(会遇到全局锁,后续会讲到)。

此时,NameNode会进行一系列的check,如是否有权限,文件是否已经存在。 当通过check后,NameNode创建一个新的文件,状态为under construction,没有任何data block与之对应,否则,抛出一个IO异常

3)DistributedFileSystem 返回一个 FSDataOutputStream 给client,让它开始写入数据。

FSDataOutputStream的成员变量dfs类型为DFSClient,DFSClient在创建时,会构造一个DFSOutputStream。 当client开始写数据时, DFSOutputStream 会将file分割成 packets,然后把 packets都放在一个队列中,这个队列叫做data queue。 data queue会被DataStreamer消费。DataStreamer的负责就是,通过挑选一系列合适的datanode来存储副本,从而要求NameNode分配新的blocks。

4)一系列合适的datanode 表现为一个pipeline。假如此时备份级别是3,那么在pipeline中就有3个node。 DataStreamer将这些packets以流式传入pipeline中的第一个datanode。 这些packets将会存储在第一个datanode中。 然后因为第一个datanode中存放了第二个datanode的地址,所以它会在接收client传来的下一个packet时,会将自己已经收到的packet写入第二个datanode中。 以此类推,每个datanode在接收上级(client或者datanode)的写时,自己也会担负起写下级datanode的责任。 所以这样看来,packet对datanode的写,其实是并行的。

5)DFSOutputStream同时也维护了一个内部队列,叫做ack queue,它里面存放了所有要被datanodes确认的packets。 只有当一个packet被pipeline中的datanodes确认后,这个packet才会从ack queue中删除。 一旦需要的副本数量被创建,datanodes就会发送acknowledgment。

6)当client结束了写数据,它会在流上调用一个close()。

7) 这个close的动作,会flush所有剩余的packets到datanodes pipeline中,然后等待datanodes的acknowledgments,最后给namenode发信号说文件已完成。 namenode已经知道了文件是由哪些block组成的,所以在返回成功之前,它只需要等待那些块被最小的备份就可以了。

4. 容错过程

这部分 是大部分人比较忽视的。
当在向 datanode 写入数据失败时,将执行以下操作,这些操作对于写入数据的客户端是透明的。

首先,关闭管道,并将ack队列中的任何数据包添加到数据队列的前面,以便故障节点下游的数据节点不会丢失任何数据包。
当前块的 datanode 如果是良好的话,这个块会被赋予一个新的标识,该标识被传送到 namenode,以便如果稍后恢复失败的 datanode 时,可以将失败的 datanode 上的失败块删除。
datanode 失败的话,它将从管道中删除,然后块的其余数据将写入管道中的两个良好数据节点。
namenode 注意到该块未被复制,并且它安排在另一个节点上创建另一个副本,然后它将后续块视为正常。
客户端写入块时,多个数据节点失败是可能的, 只要它写入dfs.replication.min(默认为1),写入就会成功,并且该块将在群集中异步复制,直到达到目标复制因子(dfs.replication,默认为3)。异步复制线程会在namenode 5min 启动一次。将需要复制的块添加到复制队列。

二,读HDFS

1. 流程图

image.png-201.8kB

2. 过程步骤

1) client 读取目标文件,是通过一个FileSystem对象的open()方法。这个FileSystem对象,对HDFS来讲,就是一个DistributedFileSystem。

2)DistributedFileSystem 使用一个RPC请求,询问NameNode文件前几个block的位置。

对于每个block,namenode会根据就近原则,返回那些离client较近(根据friendly 去计算块的距离远近),而且也存储了该block的datanode地址。

3)DistributedFileSystem 返回一个 FSDataInputStream给client,让client通过它来读取文件。

FSDataOutputStream包裹了一个DFSInputStream。DFSInputStream会来管理与datanode和namenode的I/O。 client在流上调用read()。已经存储了datanode地址的DFSInputStream,接着就会连接存储文件第一个block的、且距离最近的datanode。

4)数据会以流式传回client,因此client可以在流上重复调用read。 当这个block结束后,DFSInputStream会关闭和datanode的连接,然后找到对下个block而言最好的datanode。

5)如果DFSInputStream在和datanode交流时,发生了错误,它就会尝试下一个离它最近的datanode。 DFSInputStream会记下那些失败的datanodes,以免之后的block们对它们不必要的请求。 DFSInputStream同时会对从datanode传回的数据进行验证。如果它发现了损坏的block,它想namenode报告这个情况,然后再去请求词block的下一个备份的datanode。

6)当client结束了读数据,它会在流上调用一个close()。

参考链接

Hadoop HDFS Data Read and Write Operations: https://data-flair.training/blogs/hadoop-hdfs-data-read-and-write-operations/
HDFS读写文件流程: https://blog.csdn.net/qq_20641565/article/details/53328279
HDFS dfsclient写文件过程 源码分析: http://www.cnblogs.com/ggjucheng/archive/2013/02/19/2917020.html

posted @ 2019-06-04 20:35  Zeus~  阅读(2235)  评论(0编辑  收藏  举报