读取HDFS的整体流程图如下,下面根据此图对整个操作进行大致介绍
1.调用DistributedFileSystem.open(Path path, int bufferSize)方法,主要完成初始化DFSInputStream对象的工作,并将DFSInputStream对象作为参数初始化DFSClient.DFSDataInputStream对象(DFSClient.DFSDataInputStream类继承FSDataInputStream类),并返回DFSClient.DFSDataInputStream对象给客户端;
2.在初始化DFSInputStream对象的时候,调用NameNode.getBlockLocations(String path,long offset, long length)向NameNode查询路径path的文件对应的所有block以及存放各个block块的DataNode信息,一个block块对应着多个DataNode,大致逻辑如下:
2.1)通过路径path在FSNamesystem.dir.roorDir目录树状结构中查找对应的INode节点;
2.2)从INode节点获取所有的Block对象,存入Block[]数组中;
2.3)遍历Block[]数组,查找存放此Block对象的所有DataNode信息,即BlockInfo对象的三元数组object[]的object[index*3]值,将每个Block对象以及对应所有DataNode信息封装成LocatedBlock对象;最后全部添加到List集合中;
2.4)以List集合为参数初始化LocatedBlocks对象,并赋值给DFSInputStream.locatedBlocks变量;
3.至此,客户端生成了DFSClient.DFSDataInputStream对象,并且此类引用了DFSInputStream类,即拥有了block块对应的DataNode信息(DFSInputStream.locatedBlocks变量)
客户端发起调用(DFSClient.DFSDataInputStream)FSDataInputStream.read(byte buf[], int off, int len)方法:
3.1)根据读取偏移量找到下一个需要读取的Block块;
3.2)然后找到存储此Block块的DataNode信息;
3.3)若此DataNode为本地地址,则创建一个BlockReaderLocal对象;首先与DataNode交互,根据Block块从FSDataset.volumeMap中获取"blk_blockid"文件的File对象以及对应meta文件的File对象;然后分别创建两个FileInputStream对象,最后利用这两个FileInputStream对象完成文件的读取;文件读取操作结束。
3.3)若此DataNode为远程地址,则创建一个RemoteBlockReader对象;
3.3.1)根据DataNode信息建立Socket;
3.3.2)根据Socket创建网络输出流DataOutputStream,并发送读取文件的请求信息给DataNode端;
3.3.3)根据Socket创建网络输入流DataInputStream,用于读取DataNode返回的文件内容;
4.当DataNode为远程地址,就要执行此步获取DataNode上的文件内容;DataNode端是由DataXceiverServer线程专门负责监听请求,由DataXceiver线程负责处理请求;DataXceiver线程首先从网络输入流DataInputStream中解析客户端发送的读文件请求消息参数,然后根据blockid查找对应的block文件,并写入网络输出流中;若此DataNode读取失败,则会在从Block块对应的其他DataNode中重新读取文件,即第5步操作。
阅读(575) | 评论(0) | 转发(0) |