一、剖析文件读取

客户端及与之交互的HDFS、namenode和datanode之间的数据流。如图显示读取文件时事件的发生顺序。

axios 流式读取音频 流式读取数据_hdfs数据流


1、客户端通过调用FileSyste对象的open方法来打开希望读取的文件,对于HDFS来说,这个对象是分布式文件系统的一个实例。DistributedFileSystem通过使用RPC来调用namenode,以确定文件块的起始位置,对于每一个块,namenode返回存在有该块复本的datanode地址。此外这些datanode根据他们与客户端的距离来排序。

2、 DistributedFileSystem类返回一个FSDataInputStream对象给客户端并读取数据。FSDataInputStream类转而封装DFSInputStream对象,该对象管理着datanode和namenode的I/O;

3、 客户端对这个输入流调用read()方法。

4、 存储着文件其实几个块的datanode地址的DFSInputStream随机连接距离最近的datanode,通过这个岁数据流反复调用read()方法,可以将数据从datanode传输到客户端。

5、 到达块的末端时DFSInputStream关闭与该datanode的连接,然后寻找下一个的最佳的datanode。客户端只需要读取连续的流,并且对客户端都是透明的。

6、客户端从流中读取数据时,块是按照DFSInputStream与datanode新建连接的顺序读取的。他也会根据需要访问namenode来检索一下批数据块的datanode的位置,一旦数据块完成读取,就对FSDataInputStream调用close()方法。

在读取数据的时候,如果DFSInputStream在与datanode通信出现错误时,会尝试从这个块的另外一个最临近的datanode读取数据,同时记住故障的datanode的,以保证不会重复读取该节点上后续的块。DFSInputStream也会通过校验和确认datanode发来的数据是否完整,所有损坏,则DFSInputStream 从其余的datanode读取其复本之前通知namenode。namenode会告知客户端每个佳中最佳的datanode,并让客户端直接连接到该datanode检索数据。这样,HDFS可扩展到大量的并发客户端。同时,namenode只需要响应块位置的请求,无需响应数据请求,否则随着客户端数量的增长,namenode会很快达到瓶颈。二、剖析文件写入

客户端将文件写入HDFS流程如图所示:

axios 流式读取音频 流式读取数据_hdfs写入文件_02


1、客户端通过DistributedFileSystem对象调用create()方法来创建文件。(当然append()可以,用于追加文件)

2、 DistributedFileSystem对namenode创建一个RPC调用,在文件系统的命名空间中创建一个文件,此时文件中还没有数据块。namenode执行各种不同的检查以确保这个文件不存在以及客户端有新建该文件的权限,若这些检查均通过,namenode就会为创建新文件记录一条记录;否则,文件创建失败并向客户端抛出一个IOExceptio异常。DistributedFileSystem向客户端返回一个FSDataOutputStream对象,由此客户端可以开始写入数据。FSDataOutputStream封装了一个DFSoutPutStream对象,该对象负责处理datanode和namenode之间的通信。

3、 在客户端写入数据时,DFSOutputStream将他分成一个个的数据包并写入内部队列,成为“数据队列”(data queue)。

4、DataStreamer处理的数据队列,他的责任是根据datanode列表来要求namenode分配适合的新块来存储数据复本。这个datanode构成一个管线,管线中的节点数与复本树相同。DataStreamer将数据包流式传输到管线中的第一个datanode,该datanode存储数据包并将他发送给管弦中的第二个datanode。铜牙根第2个datanode存储该数据包并且发送给管线中的第3个datanode。

5、DFsOutputStream也维护着一个内部数据包队列来等待datanode的收到确认回执,称为”确认队列”(ask queue)。收到管道中所有datanode确认信息后,该数据包才会确认队列删除。

6、客户端完成数据写入后,对数据流调用close()方法。

7、调用close()方法将剩余的所有数据包写入datanode管线,并联系到namenode且发送文件写入完成信号之前,等待确认。

8、如果数据在写入时datanode发生故障,则执行以下操作:
(1)关闭管线,确认把队列中的所有数据包都添加回数据队列的最前端,以确保故障节点下游的datanode不会漏掉任何一个数据包。
(2)为存储在另一正常的datanode的当前数据块制定一个新的标识,并将该标识传递给namenode,以便故障datanode在恢复后可以删除存储的部分数据块。
(3)从管线中删除故障数据节点并且把余下的数据块写入管线中另外两个正常的datanode。
(4) namenode注意到块复本量不足时,会在另一个新的节点上创建一个新的副本。。后续的数据块继续正常接收处理。
在一个块被写入期间可能会有多个datanode同时发生故障(非常少见),只要写入了dfs.replication.min的复本数(默认是1),写操作就会成功,并且这个块可以在集群中异步复制,直到达到其目标复本数(dfs.replication的默认值是3)

三、一致模型
文件系统的一致模型描述了文件读/写的数据可见性。HDFS提供了一个方法来使所有缓存与数据节点强行同步即对FSDataOutputSteam调用sync()方法。当sync()方法返回成功后,对于所有新的reader而言,HDFS能保证文件中到目前为止写入的数据均达到所有datanode的写入管道并且对所有新的reader均可见。调用sync()方法可以避免在客户端或者系统发生故障时,可能会数据丢失。