接着讲另外几个数据结构。
1.CorruptReplicationMap
成员变量:Map<Block, Collection<DatanodeDescriptor>> corruptReplicasMap用来记录datanode上出错的block,getNodes方法返回一个block在哪些datanode上的副本是corrupt的。在FSNamesystem中使用corruptReplicas保存这个map结构。
坏掉的block将放入recentInvalidateSets(Map<String, Collection<Block>>)中,Client或者datanode 通过reportBadBlocks报告出错的block,namenode调用FSNamesystem的markBlockAsCorrupt方法处理。
2.recentInvalidateSets
成员变量:Map<String, Collection<Block>> recentInvalidateSets
保存了每个Datanode上无效但还存在的block(StorageID-> ArrayList<Block>)
replthread后台任务线程中的computeInvalidateWork方法(实际方法是invalidateWorkForOneNode)取出map里第一个datanode节点上所有无效的block,然后将这个block列表设置到invalidateSet集合中,namenode收到心跳信息会依据自己保存的invalidateSet集合来生成一个invalidate blocks的命令返回给datanode,让datanode来处理这些无效的block。
3.UnderReplicatedBlocks
主要的成员是一个优先队列,List<TreeSet<Block>> priorityQueues,保存副本数没有达到期望值的block。根据当前副本数低于期望值的程度决定优先级,差的越远,优先级越大(0~2,0最大)。每个优先级别对应一个TreeSet,getPriority获得优先级后决定放入哪个treeset中。
在FSNamesystem中使用neededReplications保存低于规定副本数的block信息。
涉及neededReplications的一些操作:
当datanode注册到namenode时需要校验这个datanode是否处于正准备退役阶段,是则需要检测该datanode节点上的所有block的复制数是否已经达到复制因子,如果没有则需要加入到neededReplications中 ;
当DecommissionManager的监控线程dnthread执行检测时,如果发现某个退役节点处于正准备退役阶段,则对该退役节点的所有块执行检测,查看是否达到复制因子,如果没有达到则将该block加入到neededReplications中;
当lease被删除时,需要检测和这个租约关联的文件的block数是否和期望值一致,如果小于期望值则将这个块加入到neededReplications中;
当离开安全模式时需要校验block的副本情况,如果没达到副本因子数则加入到neededReplications中;
processPendingReplications方法将pendingReplicationMonitor中监控到的超时的副本拷贝请求重新放入neededReplications中去。
4.PendingReplicationBlocks
主要的成员是Map<Block, PendingBlockInfo> pendingReplications用来保存正在复制的数据块的相关信息。该类中还有一个timerThread,检测副本是否超时的线程;副本拷贝超时(5min)未成功的block 放入到ArrayList<Block> timedOutItems中。
超时的block在FSNamesystem的processPendingReplications方法中又将 timedOutItems 清空, 添加到neededReplications中。
5.excessReplicateMap
Map<String, Collection<Block>> excessReplicateMap
保存Datanode上有效但需要删除的数据块(StorageID -> TreeSet<Block>)比如一个Datanode故障恢复后,上面的数据块在系统中副本数太多,需要删除一些数据块。
6. LeaseManager
hdfs支持write-once-read-many,也就是说不支持并行写,那么对读写的互斥同步就是靠Lease实现的。Lease说白了就是一个有时间约束的锁。客户端写文件时需要先申请一个Lease,对应到namenode中的LeaseManager,客户端的client name就作为一个lease的holder,即租约持有者。LeaseManager维护了文件的path与lease的对应关系,还有clientname->lease的对应关系。LeaseManager中有两个时间限制:softLimit and hardLimit。
软限制就是写文件时规定的租约超时时间,硬限制则是考虑到文件close时未来得及释放lease的情况强制回收租约。
LeaseManager中还有一个Monitor线程来检测Lease是否超过hardLimit。而软租约的超时检测则在DFSClient的LeaseChecker中进行。
当客户端(DFSClient)create一个文件的时候,会通过RPC 调用 namenode 的createFile方法来创建文件。进而又调用FSNameSystem的startFile方法,又调用 LeaseManager 的addLease方法为新创建的文件添加一个lease。如果lease已存在,则更新该lease的lastUpdate (最近更新时间)值,并将该文件的path对应该lease上。之后DFSClient 将该文件的path 添加 LeaseChecker中。文件创建成功后,守护线程LeaseChecker会每隔一定时间间隔renew该DFSClient所拥有的lease。
另外还有一个数据结构:datanodemap,它保存了StorageID -> DatanodeDescriptor的映射,用于保证DataNode使用的Storage的一致性。
至此,namenode上的关键数据结构已经基本上讲完了。
接下来就是namenode上的一些监控线程。
1. HeartbeatMonitor thread
datanode周期性通过RPC调用sendHeartbeat向namenode汇报自身的状态,心跳监控线程对dn和nn之间的心跳进行周期性检测,每隔时间heartbeatRecheckInterval 就执行操作heartbeatCheck()。
heartbeatCheck找到heartbeats中的dead nodes,然后从heartbeats 、clusterMap 、blocksmap这些结构中移除这些dead nodes的信息。