对namenode启动时的相关操作及相关类有一个大体了解,后续深入研究时,再对本文进行补充

>实现类

HDFS启动脚本为$HADOOP_HOME/sbin/start-dfs.sh,查看start-dfs.sh可以看出,namenode是通过bin/hdfs命令来启动

  1. $ vi start-dfs.sh
  2.  
  3. # namenodes
  4. NAMENODES=$($HADOOP_PREFIX/bin/hdfs getconf -namenodes)
  5. echo "Starting namenodes on [$NAMENODES]"
  6. "$HADOOP_PREFIX/sbin/hadoop-daemons.sh" \
  7. --config "$HADOOP_CONF_DIR" \
  8. --hostnames "$NAMENODES" \
  9. --script "$bin/hdfs" start namenode $nameStartOpt
  10. #---------------------------------------------------------

查看$HADOOP_HOME/bin/hdfs,可以找到namenode启动所调用的java类。

  1. $ vi bin/hdfs:
  2.  
  3. if [ "$COMMAND" = "namenode" ] ; then
  4. CLASS='org.apache.hadoop.hdfs.server.namenode.NameNode'
  5. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_NAMENODE_OPTS"

>源码查看

按照前文hadoop2.5.2学习及实践笔记(二)——编译源代码及导入源码至eclipse步骤,源码已经导入到eclipse中,快捷键ctrl+shift+R搜索并打开NameNode.java查看源码

NameNode类中有一个静态代码块,表示在加载器加载NameNode类过程中的准备阶段,就会执行代码块中的代码。HdfsConfiguration的init()方法的方法体是空的,这里的作用是触发对HdfsConfiguration的主动调用,从而保证在执行NameNode类相关调用时,如果HdfsConfiguration类没有被加载和初始化,先触发HdfsConfiguration的初始化过程。

  1. //org.apache.hadoop.hdfs.server.namenode.NameNode.java
  2.  
  3. static{
  4. //HdfsConfiguration类init()方法:public static void init() {}
  5. HdfsConfiguration.init();
  6. }

查看其main方法,可以看出namenode相关操作的主要入口方法是createNameNode(String argv[], Configuration conf)方法。

  1. //org.apache.hadoop.hdfs.server.namenode.NameNode.java
  2.  
  3. public static void main(String argv[]) throws Exception {
  4. if (DFSUtil.parseHelpArgument(argv, NameNode.USAGE, System.out, true)) {
  5. System.exit(0);
  6. }
  7.  
  8. try {
  9. //打印namenode启动或关闭日志信息
  10. StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);
  11. //namenode相关主要操作
  12. NameNode namenode = createNameNode(argv, null);
  13. if (namenode != null) {
  14. //向客户端和datanode提供RPC服务,直到RPC服务器结束运行
  15. namenode.join();
  16. }
  17. } catch (Throwable e) {
  18. LOG.fatal("Exception in namenode join", e);
  19. terminate(1, e);
  20. }
  21. }

createNameNode方法中通过一个switch语句对不同的命令执行不同的操作。比如搭建环境时格式化文件系统时的操作,可以查看FORMAT分支。

  1. //org.apache.hadoop.hdfs.server.namenode.NameNode.java
  2.  
  3. public static NameNode createNameNode(String argv[], Configuration conf)
  4. throws IOException {
  5. LOG.info("createNameNode " + Arrays.asList(argv));
  6. if (conf == null)
  7. conf = new HdfsConfiguration();
  8. //参数为空时默认: -regular
  9. StartupOption startOpt = parseArguments(argv);
  10. if (startOpt == null) {
  11. printUsage(System.err);
  12. return null;
  13. }
  14. setStartupOption(conf, startOpt);
  15.  
  16. switch (startOpt) {
  17. case FORMAT: {//格式化文件系统,伪分布式环境搭建时调用过namenode -format命令
  18. boolean aborted = format(conf, startOpt.getForceFormat(),
  19. startOpt.getInteractiveFormat());
  20. terminate(aborted ? 1 : 0);
  21. return null; // avoid javac warning
  22. }
  23. case GENCLUSTERID: {
  24. System.err.println("Generating new cluster id:");
  25. System.out.println(NNStorage.newClusterID());
  26. terminate(0);
  27. return null;
  28. }
  29. case FINALIZE: {
  30. System.err.println("Use of the argument '" + StartupOption.FINALIZE +
  31. "' is no longer supported. To finalize an upgrade, start the NN " +
  32. " and then run `hdfs dfsadmin -finalizeUpgrade'");
  33. terminate(1);
  34. return null; // avoid javac warning
  35. }
  36. case ROLLBACK: {
  37. boolean aborted = doRollback(conf, true);
  38. terminate(aborted ? 1 : 0);
  39. return null; // avoid warning
  40. }
  41. case BOOTSTRAPSTANDBY: {
  42. String toolArgs[] = Arrays.copyOfRange(argv, 1, argv.length);
  43. int rc = BootstrapStandby.run(toolArgs, conf);
  44. terminate(rc);
  45. return null; // avoid warning
  46. }
  47. case INITIALIZESHAREDEDITS: {
  48. boolean aborted = initializeSharedEdits(conf,
  49. startOpt.getForceFormat(),
  50. startOpt.getInteractiveFormat());
  51. terminate(aborted ? 1 : 0);
  52. return null; // avoid warning
  53. }
  54. case BACKUP:
  55. case CHECKPOINT: {//backupnode和checkpointnode启动
  56. NamenodeRole role = startOpt.toNodeRole();
  57. DefaultMetricsSystem.initialize(role.toString().replace(" ", ""));
  58. //backupnode继承NameNode类,代码最终执行的还是NameNode的构造方法
  59. return new BackupNode(conf, role);
  60. }
  61. case RECOVER: {
  62. NameNode.doRecovery(startOpt, conf);
  63. return null;
  64. }
  65. case METADATAVERSION: {
  66. printMetadataVersion(conf);
  67. terminate(0);
  68. return null; // avoid javac warning
  69. }
  70. default: {
  71. DefaultMetricsSystem.initialize("NameNode");
  72. //启动时startOpt=“-regular”,代码执行default分支,通过构造函数返回一个namenode实例
  73. return new NameNode(conf);
  74. }
  75. }
  76. }

namenode的构造方法

  1. //org.apache.hadoop.hdfs.server.namenode.NameNode.java
  2.  
  3. public NameNode(Configuration conf) throws IOException {
  4. this(conf, NamenodeRole.NAMENODE);
  5. }
  6. protected NameNode(Configuration conf, NamenodeRole role)
  7. throws IOException {
  8. this.conf = conf;
  9. this.role = role;
  10. //获取fs.defaultFS,设置namenode地址
  11. setClientNamenodeAddress(conf);
  12. String nsId = getNameServiceId(conf);
  13. String namenodeId = HAUtil.getNameNodeId(conf, nsId);
  14. //是否启用HA
  15. this.haEnabled = HAUtil.isHAEnabled(conf, nsId);
  16. //HA状态:启用/备用
  17. state = createHAState(getStartupOption(conf));
  18. //读取dfs.ha.allow.stale.reads,设置namenode在备用状态时是否允许读操作,默认为false
  19. this.allowStaleStandbyReads = HAUtil.shouldAllowStandbyReads(conf);
  20. this.haContext = createHAContext();
  21. try {
  22. //联邦环境下,使用该方法配置一系列使用一个逻辑上的nsId组合在一起的namenode
  23. initializeGenericKeys(conf, nsId, namenodeId);
  24. //namenode初始化
  25. initialize(conf);
  26. try {
  27. haContext.writeLock();
  28. state.prepareToEnterState(haContext);
  29. //namenode进入相应状态:active state/backup state/standby state
  30. state.enterState(haContext);
  31. } finally {
  32. haContext.writeUnlock();
  33. }
  34. } catch (IOException e) {
  35. this.stop();
  36. throw e;
  37. } catch (HadoopIllegalArgumentException e) {
  38. this.stop();
  39. throw e;
  40. }
  41. }

namenode初始化方法代码

  1. //org.apache.hadoop.hdfs.server.namenode.NameNode.java
  2.  
  3. protected void initialize(Configuration conf) throws IOException {
  4. if (conf.get(HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS) == null) {
  5. String intervals = conf.get(DFS_METRICS_PERCENTILES_INTERVALS_KEY);
  6. if (intervals != null) {
  7. conf.set(HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS,
  8. intervals);
  9. }
  10. }
  11. //设置权限,根据hadoop.security.authentication获取认证方式及规则
  12. UserGroupInformation.setConfiguration(conf);
  13. //登录:如果认证方式为simple则退出该方法
  14. //否则调用UserGroupInformation.loginUserFromKeytab进行登陆,登陆使用dfs.namenode.kerberos.principal作为用户名
  15. loginAsNameNodeUser(conf);
  16.  
  17. //初始化度量系统,用于度量namenode服务状态
  18. NameNode.initMetrics(conf, this.getRole());
  19. StartupProgressMetrics.register(startupProgress);
  20.  
  21. if (NamenodeRole.NAMENODE == role) {
  22. //启动http服务器
  23. startHttpServer(conf);
  24. }
  25. //根据命令对命名空间进行操作,如:前文所述启动时加载本地命名空间镜像和应用编辑日志,在内存中建立命名空间的映像
  26. loadNamesystem(conf);
  27. //创建RPC服务器
  28. rpcServer = createRpcServer(conf);
  29. if (clientNamenodeAddress == null) {
  30. // This is expected for MiniDFSCluster. Set it now using
  31. // the RPC server's bind address.
  32. clientNamenodeAddress =
  33. NetUtils.getHostPortString(rpcServer.getRpcAddress());
  34. LOG.info("Clients are to use " + clientNamenodeAddress + " to access"
  35. + " this namenode/service.");
  36. }
  37. if (NamenodeRole.NAMENODE == role) {
  38. httpServer.setNameNodeAddress(getNameNodeAddress());
  39. httpServer.setFSImage(getFSImage());
  40. }
  41.  
  42. pauseMonitor = new JvmPauseMonitor(conf);
  43. pauseMonitor.start();
  44. metrics.getJvmMetrics().setPauseMonitor(pauseMonitor);
  45.  
  46. //启动活动状态和备用状态的公共服务:RPC服务和namenode的插件程序启动
  47. startCommonServices(conf);
  48. }

loadNamesystem(Configuration conf)方法调用FSNamesystem类的loadFromDisk(Configuration conf)。前文提到的,namenode启动时从本地文件系统加载镜像并重做编辑日志,都在此方法中实现。

  1. //org.apache.hadoop.hdfs.server.namenode.FSNamesystem.java
  2.  
  3. static FSNamesystem loadFromDisk(Configuration conf) throws IOException {
  4. //必须的编辑日志目录检查
  5. checkConfiguration(conf);
  6. //设在NNStorage,并初始化编辑日志目录。NNStorage主要功能是管理namenode使用的存储目录
  7. FSImage fsImage = new FSImage(conf,
  8. FSNamesystem.getNamespaceDirs(conf),
  9. FSNamesystem.getNamespaceEditsDirs(conf));
  10. //根据指定的镜像创建FSNamesystem对象
  11. FSNamesystem namesystem = new FSNamesystem(conf, fsImage, false);
  12. StartupOption startOpt = NameNode.getStartupOption(conf);
    if (startOpt == StartupOption.RECOVER) {
  13. namesystem.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
  14. }
  15.  
  16. long loadStart = now();
  17. try {
  18. //加载镜像、重做编辑日志,并打开一个新编辑文件都在此方法中
  19. namesystem.loadFSImage(startOpt);
  20. } catch (IOException ioe) {
  21. LOG.warn("Encountered exception loading fsimage", ioe);
  22. fsImage.close();
  23. throw ioe;
  24. }
  25. long timeTakenToLoadFSImage = now() - loadStart;
  26. LOG.info("Finished loading FSImage in " + timeTakenToLoadFSImage + " msecs");
  27. NameNodeMetrics nnMetrics = NameNode.getNameNodeMetrics();
  28. if (nnMetrics != null) {
  29. nnMetrics.setFsImageLoadTime((int) timeTakenToLoadFSImage);
  30. }
  31. return namesystem;
  32. }
  33.  
  34. private void loadFSImage(StartupOption startOpt) throws IOException {
  35. final FSImage fsImage = getFSImage();
  36.  
  37. // format before starting up if requested
  38. if (startOpt == StartupOption.FORMAT) {
  39.  
  40. fsImage.format(this, fsImage.getStorage().determineClusterId());// reuse current id
  41.  
  42. startOpt = StartupOption.REGULAR;
  43. }
  44. boolean success = false;
  45. writeLock();
  46. try {
  47. // We shouldn't be calling saveNamespace if we've come up in standby state.
  48. MetaRecoveryContext recovery = startOpt.createRecoveryContext();
  49. final boolean staleImage
  50. = fsImage.recoverTransitionRead(startOpt, this, recovery);
  51. if (RollingUpgradeStartupOption.ROLLBACK.matches(startOpt)) {
  52. rollingUpgradeInfo = null;
  53. }
  54. final boolean needToSave = staleImage && !haEnabled && !isRollingUpgrade();
  55. LOG.info("Need to save fs image? " + needToSave
  56. + " (staleImage=" + staleImage + ", haEnabled=" + haEnabled
  57. + ", isRollingUpgrade=" + isRollingUpgrade() + ")");
  58. if (needToSave) {
  59. fsImage.saveNamespace(this);
  60. } else {
  61. // No need to save, so mark the phase done.
  62. StartupProgress prog = NameNode.getStartupProgress();
  63. prog.beginPhase(Phase.SAVING_CHECKPOINT);
  64. prog.endPhase(Phase.SAVING_CHECKPOINT);
  65. }
  66. // This will start a new log segment and write to the seen_txid file, so
  67. // we shouldn't do it when coming up in standby state
  68. if (!haEnabled || (haEnabled && startOpt == StartupOption.UPGRADE)) {
  69. fsImage.openEditLogForWrite();
  70. }
  71. success = true;
  72. } finally {
  73. if (!success) {
  74. fsImage.close();
  75. }
  76. writeUnlock();
  77. }
  78. imageLoadComplete();
  79. }

hadoop2.5.2学习及实践笔记(四)—— namenode启动过程源码概览的更多相关文章

  1. hadoop2.5.2学习及实践笔记(二)—— 编译源代码及导入源码至eclipse

    生产环境中hadoop一般会选择64位版本,官方下载的hadoop安装包中的native库是32位的,因此运行64位版本时,需要自己编译64位的native库,并替换掉自带native库. 源码包下的 ...

  2. hadoop2.5.2学习及实践笔记(五)—— HDFS shell命令行常见操作

    附:HDFS shell guide文档地址 http://hadoop.apache.org/docs/r2.5.2/hadoop-project-dist/hadoop-common/FileSy ...

  3. hadoop2.5.2学习及实践笔记(三)—— HDFS概念及体系结构

    注:文中涉及的文件路径或配置文件中属性名称是针对hadoop2.X系列,相对于之前版本,可能有改动. 附: HDFS用户指南官方介绍: http://hadoop.apache.org/docs/r2 ...

  4. hadoop2.5.2学习及实践笔记(六)—— Hadoop文件系统及其java接口

    文件系统概述 org.apache.hadoop.fs.FileSystem是hadoop的抽象文件系统,为不同的数据访问提供了统一的接口,并提供了大量具体文件系统的实现,满足hadoop上各种数据访 ...

  5. hadoop2.5.2学习及实践笔记(一)—— 伪分布式学习环境搭建

    软件 工具:vmware 10 系统:centOS 6.5  64位 Apache Hadoop: 2.5.2  64位 Jdk:  1.7.0_75  64位 安装规划 /opt/softwares ...

  6. kafka原理和实践(四)spring-kafka消费者源码

    系列目录 kafka原理和实践(一)原理:10分钟入门 kafka原理和实践(二)spring-kafka简单实践 kafka原理和实践(三)spring-kafka生产者源码 kafka原理和实践( ...

  7. Spring IOC容器启动流程源码解析(四)——初始化单实例bean阶段

    目录 1. 引言 2. 初始化bean的入口 3 尝试从当前容器及其父容器的缓存中获取bean 3.1 获取真正的beanName 3.2 尝试从当前容器的缓存中获取bean 3.3 从父容器中查找b ...

  8. 【后台管理系统】—— Ant Design Pro入门学习&项目实践笔记(三)

    前言:前一篇记录了[后台管理系统]目前进展开发中遇到的一些应用点,这一篇会梳理一些自己学习Ant Design Pro源码的功能点.附:Ant Design Pro 在线预览地址. Dashboard ...

  9. Hadoop源码学习笔记之NameNode启动场景流程四:rpc server初始化及启动

    老规矩,还是分三步走,分别为源码调用分析.伪代码核心梳理.调用关系图解. 一.源码调用分析 根据上篇的梳理,直接从initialize()方法着手.源码如下,部分代码的功能以及说明,已经在注释阐述了. ...

随机推荐

  1. 【杂题总汇】Codeforces-67A Partial Teacher

    [Codeforces-67A]Partial Teacher 上周刷了一大堆小紫薯的动态规划的题

  2. ELK+kafka日志处理

    此次使用kafka代替redis,elk集群搭建过程请参考:https://www.cnblogs.com/dmjx/p/9120474.html kafka名词解释: 1.话题(Topic):是特定 ...

  3. IntelliJ IDEA 12 创建Web项目 教程 超详细版【转】

    IntelliJ IDEA 12 新版本发布 第一时间去官网看了下  黑色的主题 很给力 大体使用了下  对于一开始就是用eclipse的童鞋们 估计很难从eclipse中走出来 当然 我也很艰难的走 ...

  4. SQLSERVER 数据库恢复挂起的解决办法

    如果你的数据库还处于挂起状态,请把我下面代码的test改为你的库名,然后执行完,刷新就正常了: USE masterGOALTER DATABASE test SET SINGLE_USERGOALT ...

  5. 【PHP项目】$_SEVER详解

    $_SERVER['HTTP_ACCEPT_LANGUAGE']//浏览器语言 $_SERVER['REMOTE_ADDR'] //当前用户 IP . $_SERVER['REMOTE_HOST'] ...

  6. phpstorm 安装XeDbug

    第一步:根据phpinfo()下载相对应的Xdebug插件,Xdebug下载路径https://xdebug.org/download.php 第二步:将下载好的Xdebug放到 G:\Service ...

  7. jQuery检测判断复选框是否被选中了的几种方法

    方法一:if ($("#checkbox-id")get(0).checked) {    // do something} 方法二:if($('#checkbox-id').is ...

  8. 学习python第十二天,函数4 生成器generator和迭代器Iterator

    在Python中,这种一边循环一边计算的机制,称为生成器:generator 要创建一个generator,有很多种方法.第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个genera ...

  9. Pandas 数值计算和统计基础

    1.(1) # 基本参数:axis.skipna import numpy as np import pandas as pd df = pd.DataFrame({'key1':[4,5,3,np. ...

  10. H2数据库使用

    H2数据库使用 H2数据库介绍 H2的优势: 1.h2采用纯Java编写,因此不受平台的限制. 2.h2只有一个jar文件,十分适合作为嵌入式数据库试用. 3.性能和功能的优势 H2和各数据库特征比较 ...