Hadoop Namenode启动过程分析

Namenode启动过程分析

 我这里所讲的是hadoop-0.20.2-cdh3u1版本已regular方式启动时的代码流程分析。

 在namenode启动时会首先去构造Configuration对象,这个对象会贯穿代码的整个执行过程,不过在构造的时候它并没有去加载解析core-site.xml,hdfs-site.xml等配置文件,而是在第一次要使用到这些配置的时候才去解析,解析后保存在Configuration类里的一个Properties的对象里。在这之后才真正的去用Namenode的构造方法构造Namenode对象。

 这里简单讲一下Namenode类。在Namenode里有一个FSNamesystem类的对象,这个类才真正保存了文件系统的信息。它的内部主要是通过保存几个重要的映射来达到这个目的的,比如文件与block的映射,机器(也就是各个datanode节点)与block的映射,block与机器的映射等。除了FSNamesystem类的对象,Namenode 里还有两个Server类型的成员,Server类主要是用于RPC请求的服务端实现。为什么会有两个RPC请求的服务端实现呢?其实这只是cdh3u1版本在apache的0.20.2版本上做的二次开发。在apache的0.20.2版本里只有一个RPC请求的服务端,它处理了hadoop集群内部节点和客户端发起的所有RPC请求;然而在cdh3u1里把这两种来源的RPC请求分开来处理了,一个Server处理hadoop集群内部节点的请求,另一个Server处理来自客户端发起的RPC请求;当然,要在配置文件里配置是否使用单独一个Server来处理内部的RPC请求,否则还是会只启动一个Server来处理。个人觉得分开来处理是有好处的,这样的话内部和客户端的RPC请求不会相互影响了,也会提高客户端得到响应的速度。

 在Namenode的构造方法里会去调用initialize方法,在这个方法里才做了实质性的工作,包括启动RPC服务,启动web服务和构造FSNamesystem对象。RPC留在最后讲,这里先进一下FSNamesystem类。

 FSNamesystem类里有几个重要的数据结构,它们对应的属性是blocksMap,curruptReplicasMap,datanodeMap,recentInvalidateSets,excessReplicateMap,heartbeats。blocksMap是BlocksMap类的对象,它保存了block和blockInfo的映射(在apache的0.20.2版本里保存的是blockInfo到blockInfo的映射,),BlocksMap类(cdh3u1版)的实现与JDK里HashMap的实现类似,里面也有一个内部类用于存放实际的element,在构造BlocksMap对象的时候会计算出系统所能所能管理的block的数量,该数量是用JVM的位数和能使用的最大内存计算出来的。curruptReplicasMap也是一个map,它保存了所有损坏的block,只有block的所有副本都损坏了,该block才被认为是损坏的,如果后来又收到了该block的副本report,那么会从curruptReplicasMap里remove掉该block。datanodeMap里保存了所有的曾经连接过该namenode的datanode的描述,用DatanodeDescriptor类表示。recentInvalidateSets保存了最近失效的block,这些block被认为放在出现了某些问题的机器上。excessReplicateMap保存了机器与该机器上多余的block的映射,这些block最终会被删除掉。heartbeats里保存了当前发送心跳包的datanode节点,它是datanodeMap的一个子集。

   除了以上讲的数据结构外,FSNamesystem里还有一个重要的属性dir,它是FSDirectory的对象,这个类维护了分布式文件系统的层次结构,它内部有一个属性rootDir,INodeDirectoryWithQuota类型的,代表了文件系统的根目录。这里先讲一下层次结构的组成。Hadoop里有一个INode类,该类是构造文件系统层次结构最基础的一个类,它包含了目录和文件共有的一些属性,比如访问时间,最近修改时间,权限等。从INode类派生下来的有INodeDirectory和INodeFile两个类,分别代表了目录和文件。INodeDirectory里有一个List类型的成员children,正是有了这个成员才构筑起了文件系统的层次结构;由于文件内部不可能还有文件或目录,所以INodeFile里没有类似的成员;但是Hadoop里文件是分成许多block的,所以INodeFile里维护了一个BlockInfo的数组。另外INodeDirectoryWithQuota继承了INodeDirectory,INodeFileUnderConstruction继承了INodeFile;前者表示一个带有配额的目录,后者表示正在被客户端修改的文件,它内部保存了文件与客户端的租约。综上所述,INode,INodeDirectory,INodeFile,INodeDirectoryWithQuota,INodeFileUnderConstruction五个类共同构筑起了HDFS的文件层次结构。

  讲了hadoop是怎样构建起分布式文件系统的层次结构后,揭下来我们再来看看FSDirectory对象的创建。FSDirectory类里有一个FSImage类型的成员,而FSImage类里又有一个FSEditLog类型的成员;FSImage类代表了存放文件系统元数据的fsimage文件,FSEditLog代表了对文件系统的修改,对应的文件是edits。每次namenode启动的时候会读取fsimage文件来构造文件系统的层次结构,而且还会将edits和fsimage合并为一个新的fsimage文件。这里要注意一下,hadoop的本地存放元数据以及检查点的目录由一个特别的类Storage来表示,FSImage类就继承了Storage类。我刚开始读源码的时候,总是以为Storage就表示了分布式文件系统的目录,其实不然,它表示的是本地的存放目录。Storage类继承了StorageInfo类,StorageInfo类里是一些目录的共有信息,包括创建时间,namespaceID等;在Storage类里,有一个枚举类型StorageState表示Storage的状态,还有一个接口StorageDirType表示Storage的类型,在FSImage类里实现了这个接口,从中可以看出namenode Storage有三种类型,分别是EDITS,IMAGE ,IMAGE_AND_EDITS。其实FSDirectory的创建的主要工作就是初始化fsimage对象,真正的读取fsimage文件的操作在FSDirectory类的loadFSImage(File)方法里,该方法读取fsimage文件来构造FSDirectory类里的rootDir成员,它代表了分布式文件系统的根目录。下面是读取fsimage文件的代码:

Hadoop <wbr>Namenode启动过程分析

Hadoop <wbr>Namenode启动过程分析

Hadoop <wbr>Namenode启动过程分析

 

 

 

 

 

 在FSNamesystem对象创建完后会启动几个后台守护线程,分别是PendingReplicaitonBlocks$PendingReplicationMonitor,FSNamesystem$HeartbeatMonitor,FSNamesystem$ReplicationMonitor,LeaseManager$Monitor,DecommissionManager$Monitor。HeartbeatMonitor会定期检查已注册的数据节点发来的心跳包,每次检测的时间间隔为heartbeatRecheckInterval ,可以通过heartbeat.recheck.interval来配置;该线程会根据上次发送心跳包的时间与现在的时间差来判断是否超出heartbeatExpireInterval,若超出则认为该数据节点已dead。FSNamesystem$ReplicationMonitor线程会监视整个集群的副本数量是否满足设定的值,如果某个block的副本不足,它会选择一些datanode去copy副本,副本复制是有优先级的,副本数量越少的block具有更高的优先级,系统会首先去copy这些block。当然副本的copy是需要时间的,系统是怎么知道副本copy成功的呢?这就是PendingReplicationMonitor线程的作用了,它内部有一个成员保存了正在copy的block的信息,它会定期去检查这些在某个数据节点上copy的副本是否copy成功,如果超出了设定的时间间隔,如果超出了,那么对应的block会被放入timedOutItems里,对于这些超时的block,replicationMonitor会再交给其他数据节点复制。DecommissionManager$Monitor会监视正在退役的数据节点的状态,当某个数据节点被标示为退役状态时,系统并不能马上让该数据节点退役,而是要等该数据节点上的block被复制完成后,才能允许它退役,DecommissionManager$Monitor就是用来检测这些数据节点上的block是否满足了副本因子,只有满足了副本因子,才能允许该节点真正地退役。最后讲一下LeaseManager$Monitor。首先我们要知道hdfs上的文件是不允许被多个客户端同时操作的,那hadoop是怎样避免冲突的呢?当然是通过leaseManager了。当客户端向namenode发起请求要操作某个文件的时候,首先会得到了一个文件租约lease,一个文件租约和一个文件,一个客户端相关联;若此时其他客户端要想操作这个文件,那么它得不到这个租约,也就不能操作该文件,这样就避免了多客户端同时操作某个文件。客户端会定期去更新租约的开始时间使得该客户端可以持续操作这个文件。当客户端释放这个文件的时候,客户端也会发请求告诉服务端删除掉该租约。在客户端突然宕机来不及告诉namenode释放租约的情况下,这些租约会过期。LeaseManager$Monitor会检查那些过期的租约并释放掉,好让其他客户端能操作该文件。

最后再来谈谈hadoop的RPC框架。首先我们要搞清楚RPC框架类的继承结构。有关RPC框架所涉及的类都在ipc包下。ipc包下有三个主要的类,分别是Server,Client和RPC;RPC类里还有一个Server内部类,该内部类继承了ipc下的Server类。这里我讲的只涉及到RPC框架的服务端实现,也就是Server类和RPC类,不会涉及到Client类。在Server类里,存在Call,Listener,Responer,Connection,Handler这几个内部类;在Listener类里还有一个Reader内部类。下图是我从网上找的RPC机制图:

Hadoop <wbr>Namenode启动过程分析

当一个请求到达时,listener会选取一个reader并调用该reader得registerChannel方法将得到的socketChannel注册到reader的selector中。然后构造一个Connection,将该connection放入Server类里的connectionList成员里。源代码如下:

Hadoop <wbr>Namenode启动过程分析

 

接下来就到了reader线层的执行了,在reader的run方法里会调用listener的doRead(SelectionKey)方法,然后从selectionKey里得到Connection对象,最后再去调用connection对象的readAndProcess()方法,之后还调用了connection对象的几个方法,最后再connection的processData方法里创建一个call对象,加入到server类的call队列里。接下来就到了Handler线层的执行了。在handler的run方法里会从call队列中取出一个call对象,然后用这个call的信息去调用Server类的call方法得到一个value(其实是调用了server类保存的namenode实例的方法,通常情况下,会调用到FSNamesystem类的方法上去)。最后调用setupResponse方法将value以及这次调用所产生的其他信息,如错误信息等赋值给call对象的response属性,再调用Responser的doResponse方法将这个call加入到responseQuene中。最后就剩下一个Responser了,该线程的工作很简单,也就是从responseQuene中取出call,将这次调用的结果发回给客户端,再关闭连接而已。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可能是以下原因导致hadoop namenode启动不了: 1.配置文件错误:检查hadoop配置文件中的参数是否正确设置,特别是hdfs-site.xml和core-site.xml文件。 2.权限问题:检查hadoop文件系统的权限是否正确设置,确保hadoop用户对文件系统有足够的权限。 3.端口冲突:检查hadoop namenode所使用的端口是否被其他进程占用,可以使用netstat命令查看端口占用情况。 4.磁盘空间不足:检查hadoop namenode所在的磁盘空间是否足够,如果磁盘空间不足,可能会导致hadoop namenode启动失败。 5.日志文件错误:检查hadoop namenode的日志文件,查看是否有错误信息,根据错误信息进行排查和解决。 希望以上信息能够帮助您解决hadoop namenode启动不了的问题。 ### 回答2: 首先,需要检查hadoop namenode的日志以查找任何错误信息。可以通过以下命令访问hadoop日志: cd /hadoop/logs tailf hadoop-hdfs-namenode-*.log 如果没有错误信息,则可以进一步检查以下内容: 1. 确认hadoop的配置文件是否正确配置。namenode的配置文件通常在/hadoop/etc/hadoop/hdfs-site.xml中。可以检查以下参数是否设置正确: <property> <name>dfs.namenode.rpc-address</name> <value>namenode-hostname:8020</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/hadoop/hdfs/name</value> </property> <property> <name>dfs.replication</name> <value>3</value> </property> 2. 检查hadoop的文件系统是否正确格式化。如果文件系统未正确格式化,则namenode可能无法启动。可以通过以下命令格式化文件系统: hadoop namenode -format 3. 检查系统资源是否足够。namenode需要足够的内存和硬盘空间来持久性存储文件系统的元数据。可以通过使用以下命令检查系统资源: free -mh df -h 4. 检查网络连接是否正常。namenode的启动需要依赖于网络连接。可以使用以下命令检查网络连接: ping namenode-hostname 如果上述方法都无法解决问题,则建议尝试重新安装hadoop并重新配置namenode。或联系hadoop社区,以寻求更深入的支持。 ### 回答3: 当Hadoop Namenode不能启动时,可能会发生多种原因。下面列出了几个常见的问题及其解决方案。 1. 数据目录中的文件损坏或丢失 - 在Hadoop中,Namenode存储了整个文件系统的名称空间及其文件的元数据。如果数据目录中的某些文件已损坏或丢失,Namenode将无法启动。解决此问题的方法是尝试恢复这些文件或在安装备份副本之后重新格式化Namenode。 2. 内存不足 - 如果您的机器没有足够的内存来支持Namenode进程,则可能会出现启动失败的问题。您可以通过增加内存或禁用其他应用程序以释放一些内存来解决此问题。 3. 配置文件错误 - 如果您最近对Hadoop配置文件(如core-site.xml和hdfs-site.xml)进行了更改,并且更改不正确,则可能会导致Namenode无法启动。请检查配置文件并确保它们正确配置。 4. 端口冲突 - Namenode启动需要侦听不同的端口以接收客户端请求。如果其他进程正在使用相同的端口,则会发生端口冲突,并且Namenode将无法启动。您可以通过查找并杀死占用该端口的进程来解决此问题,并将其更改为其他未使用的端口。 5. 文件系统权限问题 - Namenode需要对数据目录和元数据文件具有适当的访问权限才能启动。如果权限不正确,则可能会出现启动失败的问题。请确保Hadoop用户具有适当的读取和写入权限,以及对Namenode文件具有所有权。 6. Java版本不兼容 - Namenode需要与Hadoop兼容的Java版本。如果Java版本过低或过高,可能会导致Namenode启动失败。请确保您的Java版本符合Hadoop的要求。 总之,启动失败的问题可能有很多原因。您需要审查错误日志以确定具体原因,并采取相应的解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值