HDFS 如何写入文件?
HDFS的文件写入原理,主要包括以下几个步骤:
1.客户端通过调用DistributedFileSystem的create方法,创建一个新的文件。
2.DistributedFileSystem通过RPC(远程过程调用)调用NameNode,去创建一个没有blocks关联的新文件。创建前,NameNode 会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过,NameNode就会记录下新文件,否则就会抛出IO异常。
3.前两步结束后会返回 FSDataOutputStream 的对象,和读文件的时候相似,FSDataOutputStream 被封装成 DFSOutputStream,DFSOutputStream 可以协调 NameNode和 DataNode。客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小packet,然后排成队列 data queue。
4.DataStreamer 会去处理接受 data queue,它先问询 NameNode 这个新的 block 最适合存储的在哪几个DataNode里,比如重复数是3,那么就找到3个最适合的 DataNode,把它们排成一个 pipeline。DataStreamer 把 packet 按队列输出到管道的第一个 DataNode 中,第一个 DataNode又把 packet 输出到第二个 DataNode 中,以此类推。
5.DFSOutputStream 还有一个队列叫 ack queue,也是由 packet 组成,等待DataNode的收到响应,当pipeline中的所有DataNode都表示已经收到的时候,这时akc queue才会把对应的packet包移除掉。
6.客户端完成写数据后,调用close方法关闭写入流。
7.DataStreamer 把剩余的包都刷到 pipeline 里,然后等待 ack 信息,收到最后一个 ack 后,通知 DataNode 把文件标示为已完成。
第一,客户端通过调用DistributedFileSystem对象中的creat()函数创建一个文件,DistributedFileSystem通过RPC调用在NameNode的文件系统命名空间中创建一个新文件,此时还没有相关的DataNode与之关联。
第二,NameNode会通过多种验证保证新的文件不存在于文件系统中,并且确保请求客户端拥有创建文件的权限。当所有验证通过时,NameNode会创建一个新文件的记录,如果创建失败,则抛出一个IOExceptinn异常;如果成功,则DistrihutedFiieSystem返回一个FSDataOutputStream给客户端用来写入数据。这里FSDataOutputStream和读取数据时的FSDataInputStream一样都包含一个数据流对象DFSOutputStream,客户端将使用它来处理与DataNode和NameNode之间的通信。
第三,当客户端写入数据时,DFSOutputStream会将文件分割成包,然后放入一个内部队列,我们称为“数据队列”。DataStreamer会将这些小的文件包放入数据流中,DataStreamer的作用是请求NameNode为新的文件包分配合适的DataNade存放副本。返回的DataNode列表形成一个“管道”,假设这里的副本数是3,那么这个管道中就会有3个DataNode, DataStreamer将文件包以流的方式传送给队列中的第一个DataNode。第一个DataNDode会存储这个包,然后将它推送到第二个DataNode中,随后照这样进行,直到管道中的最后一个DataNode。
第四,DFSOutputStream同时也会保存一个包的内部队列,用来等待管道中的DataNode返回确认信息,这个队列被称为确认队列〔ack queue)。只有当所有管道中的DataNode都返回了写入成功的返回信息文件包,才会从确认队列中删除。
当然,HDFS会考虑写入失败的情况,当数据写入节点失败时,HDFS会做出以下反应。首先管道会被关闭,任何在确认通知队列中的文件包都会被添加到数据队列的前端,这样管道中失败的DataNode都不会丢失数据。当前存放在正常工作的DataNode之上的文件块会被赋予一个新的身份,井且和NameNode进行关联,这样,如果失败的DataNode过段时间后会从故障中恢复出来。其中的部分数据块就会被删除。然后,管道会把失败的DataNode删除,文件会继续被写到管道中的另外两个DataNode中。最后,NameNode会注意到现在的文件块副本数没有达到配置属性要求,会在另外的DataNode上重新安排创建一个副本,随后的文件会正常执行写入操作。
当然,在文件块写入期间,多个DataNode同时出现故障的可能性存在,但是很小。只要dfs.replicatinn.min的属性值(默认为1)成功写入,这个文件块就会被异步复制到集群的其他 DataNode中,直到满足dfs. rcplication. min的属性值(默认为3)。
客户端成功完成数据写入的操作后,就会调用6种close()函数关闭数据流。这步操作会在连接NameNode确认文件写入完全之前将所有剩下的文件包放入DataNode管道,等待通知确认信息.NameNode会知道哪些块组成一个文件(通过DataStreamer获得块位置信息),这样NameNode只要在返回成功标志前等待块被最小量(dfs.replication.min )复制即可。
本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5080350.html,如需转载请自行联系原作者