HDFS的文件操作流
熟悉HDFS的人可能知道,当我们调用DistributedFileSystem的create方法时,将会返回一个FSDataOutputStream对象,通过这个对象来对文件进行数据的写入。还是贴一张该对象的类图吧!
现在,我们以调用FSDataOutputStream的write(byte[],int,int)为例来看看HDFS是如何完成文件的数据写入操作的。先see一下这个过程的序列图:
从上图中,我们可以很容易的看出,文件的写入操作,关键是是要看DFSOutputSream,所以,下面我将详细的讨论DFSOutputSream类。
当创建一个DFSOutputSream实例的时候,它会首先根据设置的一个packet的大小和一个校验块的大小来计算一个packet应该包含多少个校验块(数据块+加校验和)以及这个packet的实际大小。源代码如下:
其中,原始的packet的大小来自配置文件中参数dfs.write.packet.size的设置,校验数据块的大小来自配置文件中参数io.bytes.per.checksum的设置。然后调用ClientProtocol的create远程方法,最后启动线程DataStreamer。整个创建过程的源代码如下:
现在,一切问题就都纠结在DataStream到底是个啥东东,究竟干了些神马勾当才能和DataNode节点联系起来呢?
实际上,在DataStream中,它总是不停的从packet队列中取出待发送的packet给DataNode节点,当然在这个过程中,它要不断地向NameNode节点申请Blocks,即:当没有Block或申请的一个Block已满时,它会调用ClientProtocol的addBlock远程方法得到一个LocatedBlock,也就是要知道它应该要把这个Block的packet发送到那些DataNode节点上。当然,HDFS对于Block的副本copy采用的是流水线作业的方式:client把数据Block只传给一个DataNode,这个DataNode收到Block之后,传给下一个DataNode,依次类推,...,最后一个DataNode就不需要下传数据Block了。噢,当DataStream把一个Block的所有Packet传送完毕之后,必须要等待所有的Packet被ack之后才能重新申请新的Block来传送后面的packet。