1. 读流程的详解
读操作:
- hdfs dfs -get /file02 ./file02- hdfs dfs -copyToLocal /file02 ./file02- FSDataInputStream fsis = fs.open("/input/a.txt");- fsis.read(byte[] a)- fs.copyToLocal(path1,path2)
官网图如下:

详细图解

1. 客户端通过调⽤FileSystem对象的open()⽅法来打开希望读取的⽂件,对于 HDFS来说,这个对象是DistributedFileSystem,它通过使⽤远程过程调⽤(RPC) 来调⽤namenode,以确定⽂件起始块的位置
2. 对于每⼀个块,NameNode返回存有该块副本的DataNode地址,并根据距离客户端 的远近来排序。3. DistributedFileSystem实例会返回⼀个FSDataInputStream对象(⽀持⽂ 件定位功能)给客户端以便读取数据,接着客户端对这个输⼊流调⽤read()⽅法4. FSDataInputStream随即连接距离最近的⽂件中第⼀个块所在的DataNode,通过 对数据流反复调⽤read()⽅法,可以将数据从DataNode传输到客户端5. 当读取到块的末端时,FSInputStream关闭与该DataNode的连接,然后寻找下⼀ 个块的最佳DataNode6. 客户端从流中读取数据时,块是按照打开FSInputStream与DataNode的新建连接 的顺序读取的。它也会根据需要询问NameNode来检索下⼀批数据块的DataNode的位 置。⼀旦客户端完成读取,就对FSInputStream调⽤close⽅法注意:在读取数据的时候,如果FSInputStream与DataNode通信时遇到错误,会尝 试从这个块的最近的DataNode读取数据,并且记住那个故障的DataNode,保证后续不 会反复读取该节点上后续的块。FInputStream也会通过校验和确认从DataNode发来 的数据是否完整。如果发现有损坏的块,FSInputStream会从其他的块读取副本,并将损坏的块通知给NameNode
2. 写流程的详解
写操作:- hdfs dfs -put ./file02 /file02- hdfs dfs -copyFromLocal ./file02 /file02- FSDataOutputStream fsout = fs.create(path);fsout.write(byte[])- fs.copyFromLocal(path1,path2)
官网图如下:

详细图解

图中的1和2. 客户端(操作者)通过调⽤DistributedFileSystem对象的create()⽅ 法(内部会调⽤HDFSClient对象的 create()⽅法),实现在namenode上创建新的⽂件并返回⼀个FSDataOutputStream 对象
1)DistributedFileSystem要通过RPC调⽤namenode去创建⼀个没有blocks关联的 新⽂件,此时该⽂件中还没有相应的 数据块信息2)但是在新⽂件创建之前,namenode执⾏各种不同的检查,以确保这个⽂件不存在以及 客户端有新建该⽂件的权限。如果 检查通过,namenode就会为创建新⽂件记录⼀条 事务记录(否则,⽂件创建失败并向客户端抛出⼀个IOException异常)。 DistributedFileSystem向客户端返回⼀个FSDataOuputStream对象3.FSDataOutputStream被封装成DFSOutputStream。DFSOutputStream能够协调 namenode和datanode。客户端开始 写数据到DFSOutputStream, DFSOutputStream会把数据分成⼀个个的数据包(packet),并写⼊⼀个内部队列,这 个队列称为“数据队列”(data queue)4.DataStreamer会去处理接受data quene,它先询问namenode这个新的block最适合存储的在哪⼏个datanode⾥(⽐⽅副本数是3。那么就找到3个最适合的 datanode),把他们排成⼀个pipeline。DataStreamer把packet按队列输出到管道的第⼀个datanode中。第⼀个datanode⼜把packet输出到第⼆个datanode 中。以此类推。DataStreamer在将⼀个 个packet流式的传到第⼀个DataNode节点后,还会将packet从数据队列移动到另⼀个队列确认队列(ack queue)中.确认队列也是由packet组成,作⽤是等待datanode完全接收完数据后接收响应.5.datanode写⼊数据成功之后,会为ResponseProcessor线程发送⼀个写⼊成功的 信息回执,当收到管道中所有的datanode确认信息后,ResponseProcessoer线程会 将该数据包从确认队列中删除。6.客户端写完数据后会调⽤close()⽅法,关闭写⼊流.7.DataStreamer把剩余的包都刷到pipeline⾥,然后等待ack信息,收到最后⼀个 ack后,客户端通过调⽤DistributedFileSystem对象的complete()⽅法来告知 namenode数据传输完成.
注意点1 如果任何datanode在写⼊数据期间发⽣故障,则执⾏以下操作:
1. ⾸先关闭管道,把确认队列中的所有数据包都添加回数据队列的最前端,以确保故障 节点下游的datanode不会漏掉任何⼀个数据包2. 为存储在另⼀正常datanode的当前数据块制定⼀个新标识,并将该标识传送给namenode,以便故障datanode在恢复后可以删除存储的部分数据块3. 从管道中删除故障datanode,基于两个正常datanode构建⼀条新管道,余下数据 块写⼊管道中正常的datanode4. namenode注意到块复本不⾜时,会在⼀个新的Datanode节点上创建⼀个新的复 本。
注意点2
注意:在⼀个块被写⼊期间可能会有多个datanode同时发⽣故障,但概率⾮常低。只要 写⼊了dfs.namenode.replication.min的复本数(默认1),写操作就会成功,并 且这个块可以在集群中异步复制,直到达到其⽬标复本数dfs.replication的数量(默 认3)
注意点3
client运⾏write操作后,写完的block才是可⻅的,正在写的block对client是不 可⻅的,仅仅有调⽤sync⽅法。client才确保该⽂件的写操作已经全部完毕。当 client调⽤close⽅法时,会默认调⽤sync⽅法。
2万+

被折叠的 条评论
为什么被折叠?



