HDFS读取文件的客户端主要代码:
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(args[0]),conf);
FSDataInputStream in = fs.open(new Path(args[0]));
IOUtils.copyBytes(in, System.out, 4096, false);
------------------------------------------------
一.DFSClient与NameNode的交互流程
调用方法主要流程:DistributedFileSystem.open(Path f, int bufferSize) --->DFSClient.open(src) --->new DFSInputStream(String src, int buffersize, boolean verifyChecksum) --->DFSInputStream.openInfo() --->DFSInputStream.fetchLocatedBlocks()最终获取LocatedBlocks,返回DFSInputStream对象;
从fetchLocatedBlocks()方法开始讲解具体逻辑:
1.【DFSClient.callGetBlockLocations(ClientProtocol namenode,String path, long start, long length)】此方法返回获取LocatedBlocks对象;内部调用流程如下:【NameNode.getBlockLocations(String src,long offset, long length) --->FSNamesystem.getBlockLocations(String clientMachine, String src, long offset, long length)-->FSNamesystem.getBlockLocationsInternal(String src,long offset, long length, int nrBlocksToReturn, boolean doAccessTime, boolean needBlockToken)】,FSNamesystem.getBlockLocations()方法的内部处理逻辑如下:
1.1)调用getBlockLocationsInternal()方法,此方法的处理逻辑如下:
1.1.1)【dir.getFileINode(src)】根据path参数从FSNamesystem.dir中获取INodeFile对象:node(即根据路径从树形目录中找到叶子节点INodeFile对象);
1.1.2)【inode.getBlocks()】从node中获取此文件所有的block:Block[];若block==null则返回LocatedBlocks=null,若block.length=0表示是空文件则返回LocatedBlocks对象,而此对象的blocks:List<LocatedBlock>变量的集合长度等于0;否则进行往下执行;
1.1.3)根据每个block块的字节数和偏移量offset计算应该读取Block[]数组的第几个元素,已经下一次读取时的起始位置curpos;
1.1.4)获取目标DataNode集合machineSet:DatanodeDescriptor[]:获取存放此block块的DataNode集合(即在BlockInfo的object[]的三元组中查找),并排除在FSNamesystem.corruptReplicas:CorruptReplicasMap集合(已经损坏的DataNode集合)中的DataNode,具体逻辑如下:
1.1.4.1)若此block块对应的INode为正在创建的文件,且当前block块为此文件的最后一个Block块,Block中DataNode个数为零,则直接获取INodeFileUnderConstruction.targets:DatanodeDescriptor[]数组作为目标DataNode集合machineSet;
1.1.4.2)否则,遍历BlockInfo中object[]三元组的DataNode(object[index*3]),若此DataNode不在FSNamesystem.corruptReplicas集合,则添加到目标DataNode集合machineSet中;
1.1.5)【LocatedBlock(Block b, DatanodeInfo[] locs, long startOffset, boolean corrupt)】以block对象,DatanodeDescriptor数组machineSet,startOffset(偏移量),是否全部损坏来初始化LocatedBlock对象;其中LocatedBlock.locs =locs,LocatedBlock.b=b;最后将此LocatedBlock对象存入List<LocatedBlock>对象中;
1.1.6)遍历1.4-1.5步,找出此次读取的N个Block块的LocatedBlock集合:List<LocatedBlock>对象;
1.1.7)以List<LocatedBlock>对象为参数初始化LocatedBlocks对象,LocatedBlocks.fileLe
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(args[0]),conf);
FSDataInputStream in = fs.open(new Path(args[0]));
IOUtils.copyBytes(in, System.out, 4096, false);
------------------------------------------------
一.DFSClient与NameNode的交互流程
调用方法主要流程:DistributedFileSystem.open(Path f, int bufferSize) --->DFSClient.open(src) --->new DFSInputStream(String src, int buffersize, boolean verifyChecksum) --->DFSInputStream.openInfo() --->DFSInputStream.fetchLocatedBlocks()最终获取LocatedBlocks,返回DFSInputStream对象;
从fetchLocatedBlocks()方法开始讲解具体逻辑:
1.【DFSClient.callGetBlockLocations(ClientProtocol namenode,String path, long start, long length)】此方法返回获取LocatedBlocks对象;内部调用流程如下:【NameNode.getBlockLocations(String src,long offset, long length) --->FSNamesystem.getBlockLocations(String clientMachine, String src, long offset, long length)-->FSNamesystem.getBlockLocationsInternal(String src,long offset, long length, int nrBlocksToReturn, boolean doAccessTime, boolean needBlockToken)】,FSNamesystem.getBlockLocations()方法的内部处理逻辑如下:
1.1)调用getBlockLocationsInternal()方法,此方法的处理逻辑如下:
1.1.1)【dir.getFileINode(src)】根据path参数从FSNamesystem.dir中获取INodeFile对象:node(即根据路径从树形目录中找到叶子节点INodeFile对象);
1.1.2)【inode.getBlocks()】从node中获取此文件所有的block:Block[];若block==null则返回LocatedBlocks=null,若block.length=0表示是空文件则返回LocatedBlocks对象,而此对象的blocks:List<LocatedBlock>变量的集合长度等于0;否则进行往下执行;
1.1.3)根据每个block块的字节数和偏移量offset计算应该读取Block[]数组的第几个元素,已经下一次读取时的起始位置curpos;
1.1.4)获取目标DataNode集合machineSet:DatanodeDescriptor[]:获取存放此block块的DataNode集合(即在BlockInfo的object[]的三元组中查找),并排除在FSNamesystem.corruptReplicas:CorruptReplicasMap集合(已经损坏的DataNode集合)中的DataNode,具体逻辑如下:
1.1.4.1)若此block块对应的INode为正在创建的文件,且当前block块为此文件的最后一个Block块,Block中DataNode个数为零,则直接获取INodeFileUnderConstruction.targets:DatanodeDescriptor[]数组作为目标DataNode集合machineSet;
1.1.4.2)否则,遍历BlockInfo中object[]三元组的DataNode(object[index*3]),若此DataNode不在FSNamesystem.corruptReplicas集合,则添加到目标DataNode集合machineSet中;
1.1.5)【LocatedBlock(Block b, DatanodeInfo[] locs, long startOffset, boolean corrupt)】以block对象,DatanodeDescriptor数组machineSet,startOffset(偏移量),是否全部损坏来初始化LocatedBlock对象;其中LocatedBlock.locs =locs,LocatedBlock.b=b;最后将此LocatedBlock对象存入List<LocatedBlock>对象中;
1.1.6)遍历1.4-1.5步,找出此次读取的N个Block块的LocatedBlock集合:List<LocatedBlock>对象;
1.1.7)以List<LocatedBlock>对象为参数初始化LocatedBlocks对象,LocatedBlocks.fileLe