HDFS的文件open操作,实际上就是执行的是DistributedFileSystem的open(Path,int)函数,其中第一个函数就是文件的路径,第二个函数表示文件流的缓存大小,该函数返回的是DFSDataInputStream流。在这里,我不得不提的一点是,DFSDataInputStream是支持用户随机读的,之所以提及这一点,是因为我要在后面详细地介绍DFSDataInputStream底层的文件流是如何实现文件的随机读。
在前面我已经讲过了(见 ),DistributedFileSystem的核心是DFSClient,因此文件的open操作真正是由DFSClient来完成的,当然,DFSClient会返回一个比较底层的文件读取流DFSInputStream。接下来,我将隆重的介绍介绍DFSInputStream这个东东。先来看看DFSInputStream的属性:
在DFSInputStream的属性中,我要重点介绍一下prefetchSize、blockReader、locateBlocks、pos、blockEnd这几个属性。prefetchSize的默认值是10个block的大小,当然这可以在配置文件中设置,对应的key值是dfs.read.prefetch.size,那么他在这里有什么作用呢?从prefetchSize的默认值和locateBlocks就不难看出了,当创建DFSInputStream的时候,它会调用ClientProtocol的getBlockLocations远程方法,来从NameNode节点获取文件src在0到prefetchSize范围内的Block信息,当然喽,结果会保存到locateBlocks中。pos指出了当前文件流的指针位置,同时,DFSInputStream会根据pos来定位到具体的Block数据块,然后从Block中挑选一个DataNode,从该DataNode节点中获取到所需要的数据,数据块信息和DataNode信息分别保存到currentBlock、currentNode中,blockEnd记录当前数据块Block的结束位置。ok,现在就剩下blockReader了,从它的名字,我们貌似就可以很敏感的感觉到DFSInputStream从DataNode节点读取数据很有可能是与它密不可分的。没错,BlockReader就是负责和Block坐在的某一个DataNode节点进行网络通信,并读取该Block数据块,当然,BlockReader在读取真正的数据时,网络Input流还需要经过DataChecksum的处理,来保证数据的可靠性。对于DFSInputStream的随机读,可以改变当前文件流的指针来实现,即改变pos的值,然后根据pos的值来重新定位到对应的数据块Block。关于DistributedFileSystem的open操作,还是整张图吧!
当然,本文介绍的重点主要放在了客户端上,而关于NameNode的open文件操作,我将在以后给大家详细的介绍。