HDFS写入数据的流程

  1. 首先客户端通过DistributedFileSystem对象调用create()方法创建文件。这时DistributedFileSystem会创建一个DFSOutPutStream,通过PRC调用让NameNode执行同名方法。NameNode此时会进行一系列的检查,包括这个文件是否存在、客户端是否拥有对该文件的权限、自身是否处于正常状态等等。若检查通过NameNode会记录创建操作到编辑日志中,此时文件还没有相应的数据块。
  2. DFSOutPutStream是在create()方法中创建的,create()方法的返回值是OutputStream,此处返回的是它的子类DFSOutPutStram的FSDataOutpuStream对象。FSDataOutpuStream会调用addBlock()方法向NameNode申请数据块,返回一个LocatedBlock对象。LocatedBlock对象中的成员变量里面记录了新数据块的标识、版本号,以及对象中的locs数组包含了数据块及其副本的信息(包含了数据块应该保存在哪个数据节点上)。
  3. 客户端通过DFSOutPutStream与DataNode建立数据流管道。管道建立起来之后,客户端就会通过FSDataOutputStream写数据了,写入FSDataOutputStream的数据会被拆分成一个个数据包放到DFSOutPutStram的内部队列dataqueue里。接着DataStreamer线程会不断从dataqueue里取出数据包发送到数据流管道的第一个数据节点中,并且还会将这个数据包放到ackqueue队列里。ResponseProcessor线程接收从Datanode发送过来的ack,如果是一个成功的ack,表示复制Pipeline中的所有Datanode都已经接收到这个Packet(数据包),ResponseProcessor线程将packet从队列ackQueue中删除。
    在发送过程中,如果发生错误,所有未完成的Packet都会从ackQueue队列中移除掉,然后重新创建一个新的Pipeline,排除掉出错的那些DataNode节点,接着DataStreamer线程继续从dataQueue队列中发送Packet,从而确保了数据不会被丢失。
    注:
    (a)DataStreamer线程是在往DFSOutPutStream的内部队列添加数据包时启动的,之后这个线程的run()方法会一直运行取出package,出错时错误处理也是在DataStreamer的run()方法里面进行出。
    (b)ResponseProcessor线程也是由DataStreamer线程启动的,出错时会将ResponseProcessor线程关闭。
    (c)每个Packet大小为64k字节,每个Packet又由一组chunk和这组chunk对应的checksum数据组成,默认chunk大小为512字节,每个checksum是对512字节数据计算的校验和数据。
  4. 数据包会写入管线中的第一个DataNode,第一个DataNode将数据写入第二个,依次类推。当收到了所有的DataNode的写成功的确认信息,则在确认队列中将该数据包删除。
  5. 当数据块写满后,会通过blockReceive()方法向namenode提交已经写完的数据块。若此时数据队列中还有数据未写完,则继续通过addblock方法向namenode申请数据块,继续上述步骤。addblock方法每次并不是只会返回一个数据块信息,而是返回多个,这样能够有效减少客户端与NameNode的通信次数。
  6. 当全部写完之后通过complete方法通知名字节点关闭文件,完成数据的写。

你可能感兴趣的:(HDFS)