• Hadoop源码分析hdfs(2)NameNode类探索


    NameNode类成分

    首先来一张NameNode类的截图

    1. NameNode 类继承了ReconfigurableBase 类 实现了 NameNodeStatusMXBean 接口
    2. NameNode 类中有一枚举类 OperationCategory ‘’
    3. 有一内部类NameNodeHAContext
    4. 有一静态块(static class initializer)

    启动脚本后流程

    之前看到启动脚本执行了namenode 这个主类,从类结构来看,首先执行的是静态块的初始化

    //调用了  HdfsConfiguration 的init 方法
    static{
        HdfsConfiguration.init();
      }
    

    接下来看这个init()方法

    发现init 方法是空的,但是调用init()方法必然回先执行静态块

    //弃用属性名和更新后的属性名的对应关系,防止旧的属性名不可以用(再还维护的时候)
    addDeprecatedKeys();
    //加载配置文件 
    Configuration.addDefaultResource("hdfs-default.xml");
    Configuration.addDefaultResource("hdfs-site.xml");
    

    配置文件放到静态块初始化,可以实现全局唯一,单例的一种实现方式。接下来就是执行main 函数了

    public static void main(String argv[]) throws Exception {
        //检查传入的参数是不是帮助参数  例如 --help 等,是的话打印使用信息 NameNode.USAGE并退出
        if (DFSUtil.parseHelpArgument(argv, NameNode.USAGE, System.out, true)) {
          System.exit(0);
        }
    	// 不是帮助参数的话  真正执行集群相关操作
        try {
            //打印相关日志,如 starting className,hostname ,version,javaVersion,date等
          StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);
            
            //重点在这  createNameNode
          NameNode namenode = createNameNode(argv, null);
          if (namenode != null) {
            namenode.join();
          }
        } catch (Throwable e) {
          LOG.error("Failed to start namenode.", e);
          terminate(1, e);
        }
      }
    
    
    
    
    // createNameNode  方法
    
     public static NameNode createNameNode(String argv[], Configuration conf)
          throws IOException {
        LOG.info("createNameNode " + Arrays.asList(argv));
        if (conf == null)
          conf = new HdfsConfiguration();
        // Parse out some generic args into Configuration.
        GenericOptionsParser hParser = new GenericOptionsParser(conf, argv);
        argv = hParser.getRemainingArgs();
        // Parse the rest, NN specific args.
         
         //解析参数,确认具体的操作类型 例如-format
        StartupOption startOpt = parseArguments(argv);
        if (startOpt == null) {
          printUsage(System.err);
          return null;
        }
        setStartupOption(conf, startOpt);
    
        switch (startOpt) {
          //这个就是我们格式化集群的时候执行的操作,暂时先不看了,直接看case 的最后 默认的default
          case FORMAT: {
            boolean aborted = format(conf, startOpt.getForceFormat(),
                startOpt.getInteractiveFormat());
            terminate(aborted ? 1 : 0);
            return null; // avoid javac warning
          }
          case GENCLUSTERID: {
            System.err.println("Generating new cluster id:");
            System.out.println(NNStorage.newClusterID());
            terminate(0);
            return null;
          }
          case FINALIZE: {
            System.err.println("Use of the argument '" + StartupOption.FINALIZE +
                "' is no longer supported. To finalize an upgrade, start the NN " +
                " and then run `hdfs dfsadmin -finalizeUpgrade'");
            terminate(1);
            return null; // avoid javac warning
          }
          case ROLLBACK: {
            boolean aborted = doRollback(conf, true);
            terminate(aborted ? 1 : 0);
            return null; // avoid warning
          }
          case BOOTSTRAPSTANDBY: {
            String toolArgs[] = Arrays.copyOfRange(argv, 1, argv.length);
            int rc = BootstrapStandby.run(toolArgs, conf);
            terminate(rc);
            return null; // avoid warning
          }
          case INITIALIZESHAREDEDITS: {
            boolean aborted = initializeSharedEdits(conf,
                startOpt.getForceFormat(),
                startOpt.getInteractiveFormat());
            terminate(aborted ? 1 : 0);
            return null; // avoid warning
          }
          case BACKUP:
          case CHECKPOINT: {
            NamenodeRole role = startOpt.toNodeRole();
            DefaultMetricsSystem.initialize(role.toString().replace(" ", ""));
            return new BackupNode(conf, role);
          }
          case RECOVER: {
            NameNode.doRecovery(startOpt, conf);
            return null;
          }
          case METADATAVERSION: {
            printMetadataVersion(conf);
            terminate(0);
            return null; // avoid javac warning
          }
          case UPGRADEONLY: {
            DefaultMetricsSystem.initialize("NameNode");
            new NameNode(conf);
            terminate(0);
            return null;
          }
          default: {
            //MetrucsSystem 是用来给系统服务做监控,做统计的,hadoop kafka spark 等都用到了暂时先不展开看了
            DefaultMetricsSystem.initialize("NameNode");
            //返回一个namenode 对象
            return new NameNode(conf);
          }
        }
      }
    
    // 上边new NameNode 调取的构造器
    // NameNodeRole == NAMENODE
     protected NameNode(Configuration conf, NamenodeRole role)
          throws IOException {
        super(conf);
        //初始化NameNode跟踪器  
        this.tracer = new Tracer.Builder("NameNode").
            conf(TraceUtils.wrapHadoopConf(NAMENODE_HTRACE_PREFIX, conf)).
            build();
        this.tracerConfigurationManager =
            new TracerConfigurationManager(NAMENODE_HTRACE_PREFIX, conf);]
        //角色为NameNode
        this.role = role;
        //设置Namenode 的地址便于让客户端来访问 这个值是我们 配置在core-silt.xml 中的 属性:fs.defaultFS
        setClientNamenodeAddress(conf);
         // 这个一般是 参数 dfs.nameservice.id  的值,也可以是已经弃用的属性值
        String nsId = getNameServiceId(conf);
         // 配置的nnid  <dfs.ha.namenode.id>
        String namenodeId = HAUtil.getNameNodeId(conf, nsId);
         //是否是高可用
        this.haEnabled = HAUtil.isHAEnabled(conf, nsId);
         //namenode 状态  active  还是standby
        state = createHAState(getStartupOption(conf));
         //用于测试 如果在standby 模式下还允许读返回true  <dfs.ha.allow.stale.reads>的值,默认为false
        this.allowStaleStandbyReads = HAUtil.shouldAllowStandbyReads(conf);
         //初始化了内部类 NameNodeHAContext 对象(文章开始提到过)
        this.haContext = createHAContext();
        try {
            //一些地址 defaultFs , 此方法将值从格式为key.nameserviceId的特定键复制到key,以设置通用配置。 
            //完成此操作后,其余代码仅读取配置的通用版本,以实现向后兼容和更简单的代码更改。
          initializeGenericKeys(conf, nsId, namenodeId);
            //初始化namenode  ,这个方法摘抄在下边
          initialize(getConf());
          try {
            haContext.writeLock();
            state.prepareToEnterState(haContext);
            state.enterState(haContext);
          } finally {
            haContext.writeUnlock();
          }
        } catch (IOException e) {
          this.stopAtException(e);
          throw e;
        } catch (HadoopIllegalArgumentException e) {
          this.stopAtException(e);
          throw e;
        }
        this.started.set(true);
      }
    
    
    //------------------------------------------------------------------------------------------------------------------------------------
    //initialize()方法
    {
        //系统服务统计的一些设置 使用metrics框架
        if (conf.get(HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS) == null) {
          String intervals = conf.get(DFS_METRICS_PERCENTILES_INTERVALS_KEY);
          if (intervals != null) {
            conf.set(HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS,
              intervals);
          }
        }
        //hadoop 用户组的一些配置 ,用于安全认证 Kerberos
        UserGroupInformation.setConfiguration(conf);
        //获取namenode Server 的 RpcSeverAdress 然后以NameNode的已配置用户身份登录。
        loginAsNameNodeUser(conf);
    	
        //统计信息
        NameNode.initMetrics(conf, this.getRole());
        StartupProgressMetrics.register(startupProgress);
    		
        pauseMonitor = new JvmPauseMonitor();
        pauseMonitor.init(conf);
        pauseMonitor.start();
        metrics.getJvmMetrics().setPauseMonitor(pauseMonitor);
    
        if (NamenodeRole.NAMENODE == role) {
            //初始化 NameNodeHttServer 并启动 绑定地址为 <dfs.namenode.http-address>的值 默认为0.0.0.0:50070
          startHttpServer(conf);
        }
        //加载fsimage 到内存
        loadNamesystem(conf);
        //启动HadoopRpcServer   绑定地址<dfs.namenode.servicerpc-address>
        rpcServer = createRpcServer(conf);
        //备注 createRpcServer部分代码------------------------------开始
        
        this.serviceRpcServer = new RPC.Builder(conf)
              .setProtocol(
                  org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolPB.class)  //hadoop 自己实现的协议
              .setInstance(clientNNPbService)
              .setBindAddress(bindHost)
              .setPort(serviceRpcAddr.getPort()).setNumHandlers(serviceHandlerCount)
              .setVerbose(false)
              .setSecretManager(namesystem.getDelegationTokenSecretManager())
              .build();
        
        lifelineRpcServer = new RPC.Builder(conf)    //这个给lifelineRpcServer 不太清楚是干什么的
              .setProtocol(HAServiceProtocolPB.class)
              .setInstance(haPbService)
              .setBindAddress(bindHost)
              .setPort(lifelineRpcAddr.getPort())
              .setNumHandlers(lifelineHandlerCount)
              .setVerbose(false)
              .setSecretManager(namesystem.getDelegationTokenSecretManager())
              .build();
        
        
        this.clientRpcServer = new RPC.Builder(conf)
            .setProtocol(
                org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolPB.class)
            .setInstance(clientNNPbService).setBindAddress(bindHost)
            .setPort(rpcAddr.getPort()).setNumHandlers(handlerCount)
            .setVerbose(false)
            .setSecretManager(namesystem.getDelegationTokenSecretManager()).build();
        
        //备注 插入rpcServer 部分代码------------------------------结束
        
        //后退  不太清楚是什么配置
        initReconfigurableBackoffKey();
    
        if (clientNamenodeAddress == null) {
          // This is expected for MiniDFSCluster. Set it now using 
          // the RPC server's bind address.
          clientNamenodeAddress = 
              NetUtils.getHostPortString(getNameNodeAddress());
          LOG.info("Clients are to use " + clientNamenodeAddress + " to access"
              + " this namenode/service.");
        }
        if (NamenodeRole.NAMENODE == role) {
          httpServer.setNameNodeAddress(getNameNodeAddress());
            //设置加载后的系统镜像
          httpServer.setFSImage(getFSImage());
        }
        //启动服务  (东西挺多,后续补充)
        startCommonServices(conf);
        //启动一个定时器把namenode 的统计信息写入文件,可通过配置文件关闭
        startMetricsLogger(conf);
      }
    
    //------------------------------------------------------------------------------------------------------------------------------------
    
    //-- NameNode 对象的join 方法
     public void join() {
        try {
            //while server is running server.wait (serviceRpcServer/ClientRpcServer/lifelineRpcServer)
          rpcServer.join();
        } catch (InterruptedException ie) {
          LOG.info("Caught interrupted exception ", ie);
        }
      }
    
    
  • 相关阅读:
    synchronized底层实现学习
    [Alink漫谈之三] AllReduce通信模型
    Alink漫谈(二) : 从源码看机器学习平台Alink设计和架构
    Alink漫谈(一) : 从KMeans算法实现不同看Alink设计思想
    [源码分析]从"UDF不应有状态" 切入来剖析Flink SQL代码生成 (修订版)
    从"UDF不应有状态" 切入来剖析Flink SQL代码生成
    [源码分析] 带你梳理 Flink SQL / Table API内部执行流程
    [白话解析] 通俗解析集成学习之bagging,boosting & 随机森林
    [源码分析] 从FlatMap用法到Flink的内部实现
    Ceph 14.2.5-K8S 使用Ceph存储实战 -- <6>
  • 原文地址:https://www.cnblogs.com/parallelline/p/12460001.html
Copyright © 2020-2023  润新知