以下内容摘自《Hadoop权威指南》,版权归原作者所有。
流程图
流程说明
1、客户端通过对 Distributed FileSystem 对象调用 create() 函数来创建文件(步骤 1)。
2、DistributedFileSystem对namenode 创建一个 RPC 调用,在文件系统的命名空间中创建一个新文件,此时该文件中还没有相应的数据块(步骤2)。
namenode 执行各种不同的检查以确保这个文件不存在,并且客户端有创建该文件的权限。如果这些检查均通过, namenode 就会为创建新文件记录一条记录,否则,文件创建失败并向客户端抛出一个IOException 异常。
Distributed FileSystem向客户端返回一个FSDataOutputStream对象,由此客户端可以开始写入数据。就像读取事件一样,FSDataOutputStream 封装一个 DFSoutPutstream 对象,该对象负责处理 datanode与namenode 之间的通信。3、在客户端写入数据时(步骤 3),DFSOutputStream 将它分成一个个的数据包,并写入内部队列,称为”数据队列” (data queue)。
4、DataStreamer 处理数据队列,它的责任是根据 datanode 列表来要求 namenode 分配适合的新块来存储数据备份。这一组datanode 构成一个管线一一假设复本数为3,所以管线中有3个节点。DataStreamer 将数据包流式传输到管线中第1个datanode ,该 datanode 存储数据包并将它发送到管线中的第2个datanode 。同样地,第2个datanode 存储该数据包并且发送给管线中的第3个(也是最后一个 )datanode (步骤4)。
5、DFSOutputStream 也维护着一个内部数据包队列来等待 datanode 的收到确认回执,称为”确认队列” (ack queue) 。当收到管道中所有 datanode 确认信息后,该数据包才会从确认队列删除(步骤 5)。
如果在数据写入期间, datanode 发生故障,则执行以下操作,这对与写入数据的客户端是透明的。首先关闭管线,确认把队列中的任何数据包都添加回数据队列的最前端,以确保故障节点下游的 datanode 不会漏掉任何一个数据包。为存储在另一正常 datanode 的当前数据块指定一个新的标识,并将该标识传送给 namenode,以便故障 datanode 在恢复后可以删除存储的部分数据块。从管线中删除故障数据节点并且把余下的数据块写入管线中的两个正常的 datanode。 namenode 注意到块复本量不足时,会在另一个节点上创建一个新的复本。后续的数据块继续正常接受处理。
在一个块被写入期间可能会有多个 datanode 同时发生故障,但非常少见。只要写入了 dfs.replication.min 的复本数(默认为1),写操作就会成功,并且这个块可以在集群中异步复制,直到达到其目标复本数 (dfs. replication 的默认值3)。6、客户端完成数据的写入后,会对数据流调用 close()方法(步骤 6) 。
7、close()方法会将剩余的所有数据包写入 datanode 管线中,并在联系 namenode 且发送文件写入完成信号之前,等待确认(步骤 7)。namenode 已经知道文件由哪些块组成(通过 DataStreamer询问数据块的分配) ,所以它在返回成功前只需要等待数据块进行最小量的复制。