文件读取流程

    1)  客户端首先要调用FileSystem对象的静态方法open()方法来打开一个希望读取文件的路径,在HDFS中文件的对象为Path对象(与Java中的File相对应)。

    2) FileSystem对象就是一个DistributedFileSystem对象,通过利用RPC来调用NameNode节点,(NameNode节点存储着整个文件系统目录、文件以及文件所在块的位置信息),来确定我们需要打开的文件所有数据块的存储位置。文件在被存入HDFS中,会被划分为多个数据块存储的,对于每一个数据块,namenode都会返回存有该数据块副本的datanode地址。数据块副本的datanode地址会根据与客户端的距离来排序。DistributedFileSystem返回一个FSDataInputStream对象给client用来读取数据。FSDataInputStream封装了DFSInputStream对象,该对象用于管理NameNodeDataNodeI/O

   3) 客户端利用该FSDataInputStream对象的输入流调用read()方法。输入流会首先读取距离客户端最近的datanode,反复读取,直到将该datanode数据读取完后,然后就会FSDataInputStream关闭与该datanode的连接,然后继续寻找下一个datanode节点。

  4) 客户端读取文件,数据块都是按照DFSInputStream与datanode连接的距离顺序读取,也会询问namenode下一批数据块的datanode位置,整个文件读取完后,就会马上调用FSDataInputStream的close()方法。

       读取中的失败错误处理:当读取数据时,DFSInputStream与datanode通信失败,则会读取这个块的最接近该datanode的节点来读取数据,并且以后不会反复读取该失败节点。

      namenode仅仅提供给客户端检索文件的作用,告知客户端每个块最佳datanode(利用排序),它仅仅响应数据块位置的请求,而无需响应数据请求。具体的数据流都是由客户端与datanode直接通信的。


文件写入流程

   

1). client通过调用DistributedFileSystemcreate()方法来创建文件。

2). DistributedFileSystem通过RPC调用NameNode在文件系统的名字空间里创建一个新文件,名称节点首先确定文件原来不存在,并且客户端有创建文件的权限,然后创建新文件,这个时候还没有任何块的信息。DistributedFileSystem返回FSDataOutputStreamclientFSDataOutputStream封装了一个DFSOutputStream对象,该对象负责处理datanodenamenode之间的通讯。

3). 当Client开始写数据的时候,DFSOutputStream把文件的数据分成一个个数据包,并写入内部对列DataQueueDataQueue是由DataStreamer负责读取,DataStreamer通知NameNode分配DataNode,用来存储数据块(每块默认复制3),分配的DataNode列表形成一个管道(pipeline)。在上图中管道由三个datanode组成,这三个datanode的选择有一定的副本放置策略。

4).  DataStreamer将数据块流式传输到pipeline中的第一个DataNode,第一个DataNode存储数据块并将数据块发送给pipeline中的第二个DataNode,同样的,第二个DataNode存储数据块并将数据块发送给pipeline中的第三个DataNode

5). 同时,DFSOutputStream也管理ackqueue(确认队列),ackqueue里存储着等待datanode识别的数据块,只有当管道里所有datanode都返回写入成功,这个数据块才算写成功,才会从ackqueue中删除,开始写下一个数据块。

      如果某个datanode发生故障,写失败了,则会执行如下步骤,但是这些对client是透明的。

     1) 管道关闭。

     2)正常的datanode上的当前block会有一个新ID,并将该ID传送给namenode,以便失败的datanode在恢复后可以删除那个不完整的block

    3) 失败的datanode会被移出管道,余下的数据块继续写入管道的其他两个正常的datanode

    4) namenode会标记这个block的副本个数少于指定值。block的副本会稍后在另一个datanode创建。

     5)有些时候多个datanode会失败,但非常少见。只要dfs.replication.min(缺省是1)datanode成功了,整个写入过程就算成功。缺少的副本会在集群中异步的复制,直到达到正常的副本数。

6. client完成了所有block的写入后,调用FSDataOutputStreamclose()方法关闭文件。

7. FSDataOutputStream通知namenode写文件结束。
    文件写入中的副本策略:

1) Hadoop默认副本策略是将第一个复本放在运行客户端的节点上,即上传文件或者写入文件所在的datanode节点上。如果客户端不在集群中,则就随机选择一个节点。

2) 第二个复本放在与第一个复本不同且随机的另外的机架上。

3) 第三个复本与第二个复本放在相同的机架上。