DatanodeDescriptor内部结构说明
DatanodeDescriptor保存了特定Datanode上面的一些统计信息,如硬盘容量、使用量,最后更新时间等,DatanodeDescriptor结构属于Namenode的内部结构,并不通过网络向Datanode和Client传输。
DatanodeDescriptor还保存了一个BlockInfo对象,通过该BlockInfo对象能够遍历到该Datanode上面对应的所有block的信息。
DatanodeDescriptor有三个重要的内部类,分别是:
1. BlockTargetPair,该类主要保存了一个block和其对应的一组DatanodeDescriptor。
2. BlockQueue,该类是封装为BlockTargetPair的队列结构。
3. BlockIterator,该类是通过BlockInfo能够遍历该Datanode上面对应的所有block
此外,Datanode根据上面的结构保存了Datanode需要处理的三个重要的数据结构,见下表:
数据结构 |
功能 |
BlockQueue replicateBlocks |
对应了该Datanode需要传输给其它Datanode的block(DatanodeProtocol.DNA_TRANSFER) |
BlockQueue recoverBlocks |
对应了该Datanode需要从主结点进行恢复的block (DatanodeProtocol. DNA_RECOVERBLOCK) |
Set<Block> invalidateBlocks |
对应了无效的块,需要从Datanode中删除 |
这三个数据结构通过封装为BlockCommand对象,在Datanode与Namenode的RPC通信时作为Datanode在心跳汇报通信的返回值返回给Datanode,Datanode接收到对应信息后进行对应处理,具体操作下面会涉及。
添加的Block到该DatanodeDescriptor中。
从该DatanodeDescriptor中移除Block。
Datanode的心跳汇报经过处理后,更新DatanodeDescriptor的统计信息。
将block放入到replicateBlokcs结构中。
将block放入到recoverBlokcs结构中。
将block放入到invalidateBlocks结构中。
1. 根据maxTransfer尽可能多的从replicateBlocks中取出BlockTargetPair结构
2. 将该List<BlockTargetPair>结构封装为BlockCommand对象,其action为DNA_TRANSFER
1. 根据maxTransfer尽可能多的从recoverBlocks中取出BlockTargetPair结构
2. 将该List<BlockTargetPair>结构封装为BlockCommand对象,其action为DNA_RECOVERBLOCK
1. 根据maxblocks尽可能多的从invalidateBlocks中取出Block数组
2. 将该Block[]封装为BlocksCommand对象,其action为DNA_INVALIDATE
与DatanodeDescriptor的内部数据结构关系不大,主要功能是对Datanode通过RPC机制与Namenode通信传递的BlockReport进行分析,将所有的block信息与对应的DatanodeDescriptor信息进行关联。完成BlocksMap中每个Block与其相对应的Datanodes的映射。
外部方法调用上面提到的内部重要方法,改变DatanodeDescriptor中的重要数据结构,总结原有的调用流程和方法,为下一步tbfs做参考。
由于有很多方法调用了DatanodeDescriptor的方法,根据其调用方式,分为三类,一类是DataNode通过RPC机制与NameNode进行通信,修改DatanodeDescriptor的内部结构。另一类是NameNode内部通过状态检查调用DatanodeDescriptro,来修改其内部结构。还有一类是Client与NameNode RPC通信改变DatanodeDescriptor的内部结构。
Datanode通过RPC机制与NameNode通信,根据DatanodeProtocol接口定义,其中有以下两个操作会影响到DatanodeDescriptor的内部状态,分别是:
l sendHeartBeat
l blockReport
下面按照流程一一说明。
1) 用例图(返回值以调用getLeaseRecoveryCommand为例)
2) 用例说明
简要说明:DataNode通过RPC与NameNode通信进行心跳汇报,并从NameNode获得相应的BlockCommand |
流程说明:1、DataNode与NameNode进行RPC通信,传递capacity,dfsUsed等参数 2、NameNode的sendHeartBeat()转发给FSNameSystem的handleHeartBeat方法 3、handleHeartBeat检查Datanode对应状态,从注册的DatanodeDescriptor集合(datanodeMap)中获得汇报的DatanodeDescriptor对象 4、DanodeDescriptor调用updateHeartbeat,更新该DataNode对应的统计数据 5、如果DatanodeDescriptor的recoverBlocks存在,则调用DatanodeDescriptor的getLeaseRecoveryCommand方法 6、如果DatanodeDescriptor的不存在,则调用getReplicationCommand方法和getInvalidateBlocks方法,封装为一个cmd返回给Datanode,作为一次心跳汇报的返回值 |
1) 用例图
简要说明:DataNode通过RPC与NameNode通信汇报块信息,并从NameNode获得相应的DatanodeCommand |
流程说明:1、DataNode与NameNode进行RPC通信,传递long[]数组参数 2、NameNode将long[]数组解析为Block数组,调用FSNameSystem的processReport方法 3、processReport从注册的DatanodeDescriptor集合(datanodeMap)中获得对应的DatanodeDescriptro对象,并检查其状态 4、调用DatanodeDescriptor的reportDiff方法,与DatanodeDescriptor中保存的block信息进行对比,获得block的toRemove ,toAdd, toInvalidate集合 5、获得集合后分别调用removeStoredBlock,addStoredBlock,addToInvalidates方法,更新BlocksMap中信息 |
1) 用例图
简要说明:NameNode中有一个线程class ReplicationMonitor implements Runnable用来检查低于replicate状态的block,并指定需要复制到的Datanode上面,从而调用DatanodeDescriptor方法。 |
流程说明:1、周期性调用FSNameSystem的computeDatanodeWork方法 2、computeDatanodeWord首先计算需要处理的block数和node数,然后调用ComputeReplicationWork 3、ComputeRelicationWork调用chooseUnderReplicatedBlocks,根据优先级生成需要复制的block列表 4、随后按照优先级顺序循环调用computeReplicationWorkForBlock 5、在computeReplicationWordForBlock中调用chooseSourceDatanode方法,随机到找到block对应的一个没有超过replicate个数、没有corrupt、node没有decommissioned等情况的正常的DatanodeDescriptor srcNode。如果不存在任何一个这样的DatanodeDescriptor或者现存的replica加上pending的replica大于require的replica,则直接返回false 6、调用replicator的chooseTarget,找到需要复制到的datanodeDescriptor数组 7、调用在5中得到的srcNode的addBlockToBeReplicated方法,传递6中得到datanodeDescriptor数组,在下一次心跳汇报时返回给datanode进行相应处理 |
1) <!--[endif]-->用例图
简要说明:同上,用来检查无效的块,调用对应的DatanodeDescriptor方法。 |
流程说明:1、周期性调用FSNameSystem的computeDatanodeWork方法 2、computeDatanodeWork调用computeInvalidateWork方法 3、循环调用invalidateWorkForOneNode方法,直到达到预设值或全部处理完 4、invalidateWorkForOneNode方法中,从recentInvalidateSets结构中获得第一个datanode节点,找到对应的DatanodeDescriptro,同时将其所有对应invalidate block遍历出 5、将遍历出的invalidate block封装调用addBlocksToBeInvalidated方法,在下一次心跳汇报时返回给datanode进行相应处理 |
1) 用例图
简要说明:LeaseManager有一个线程class Monitor implements Runnable,周期性的检查租约情况,并处理租约指定主结点调用DatanodeDescriptor的相应方法。 |
流程说明:1、LeaseManager的Monitor线程周期性的调用LeaseManager的checkLeases方法 2、checkLease方法从sortedLeases集合中获得Lease,同时获得该Lease对应的所有NameSpace中的path,循环调用FSNameSystem中的internalReleaseLeaseOne参数为Lease和其对应的一个path,释放租约 3、FSNameSystem中的internalReleaseLeaseOne首先根据path获得对应的INodeFile检查是否在underConstruction状态。如果处于underConstruction状态,获得最后一个block,并得到对应的DatanodeDescriptor数组。 4、调用INodeFIleUnderConstruction的assignPrimaryDatanode方法,通过算法找到指定的主结点(primary),调用primary的addBlockToBeRecovered方法,设置该block复制的主结点,在下一次心跳汇报时返回给datanode进行相应处理 |
1) 用例图
与DatanodeDescriptor相关操作的用例图见上面LeaseManager的用例图。
2) 用例说明
简要说明:Client与NameNode RPC通信,调用create方法创建文件,指定主结点 |
流程说明:1、Client与NameNode通信,调用NameNode中的create方法 2、NameNode的create方法调用FSNameSystem的startFile方法 3、startFile调用startFileInternal方法,startFileInternal检查src对应的INodeFIle是否存在,如果存在检查该INodeFIle的租约情况,如果有client持有该INodeFile租约不同于操作发起的client,检查租约是否过期(expiredSoftLimit),如果过期调用internalReleaseLease方法 4、internalReleaseLease释放租约,循环调用internalReleaseLeaseOne 5、下面步骤见LeaseManager步骤的3、4 |
1) 与DatanodeDescriptor相关操作的用例图见上面LeaseManager的用例图。
2) 用例说明
简要说明:Client与NameNode RPC通信调用append方法,追加写,指定主结点 |
流程说明:1、Client与NameNode通信,调用NameNode中的append方法 2、NameNode的append方法调用FSNameSystem的appendFile方法 3、appendFIle方法调用startFileInternal,传递参数表明是append操作 4、下面步骤见create的3、4、5 |