HBase源码走读-(1)HMaster启动过程

时间:2022-09-11 16:23:26

  • 前记

断断续续使用HBase有2,3年的时间了,由于都是工作驱动,需要用到的时候才重新拿起来,过段时间又忘了差不多了,连最基本的只是还需要度娘和谷歌,感觉挺失败的,和当初希望成为大数据方面的专家背道而驰,越走越远。正好刚离职,有这个闲工夫,想了下还是需要有东西沉淀下来,不然对知识掌握上使用游击战是不行的,还是需要系统的整理这些知识点,一来可以查缺补漏,二来可以将脑中的知识片段捋一捋,更深刻,三来以后忘了,再重新看下自己的博客可以快速找回尽可能多的知识,毕竟是自己写的,比起临时看别人的博客来知识的恢复速度来的更快。

  • 走读功能点

由于HBase项目过于庞大,通篇走读整理不太现实,故暂时列出个人认为比较核心的功能电走读整理。

HMaster启动过程

HRegionServer启动过程

HBase存储结构

WAL相关

Region分裂过程

HBase数据存储查询过程

  • 正题开始

软件版本:

JDK:1.8.0_112

Maven:3.3.9

HBase:2.0.0

OS: Mac OS X 10.10.5


准备工作:

1)下载代码。https://github.com/apache/hbase

2)安装Maven。最好自己搭建一个Nexus私服,以后修改代码重新编译比较快,不用重新下这么多依赖包,直接从本地仓库脱下来就行了。

3)编译源码。编译源码是个漫长的过程,主要是下载依赖包。编译过程不是一次成功的,有时个别依赖包下不下来,需要到仓库的对应目录删掉*.lastUpdated等哪些文件,重新执行maven编译命令;另外一个就是执行

mvn compile -DSkipTests可以全部执行 success,但是mvn install -DSkipTests执行到最后一个模块的时候就报错,说是测试用例不通过,我是修改了根目录的pom.xml中Configuration项内加入

<skiTests>true</skipTests>

再执行mvn install -DSkipTests就可以了。

另外, -DMaven.test.stkip=true是测试用例代码不编译也不执行;-DSkipTests知识不执行测试用例代码

HMaster的类图如下:

HBase源码走读-(1)HMaster启动过程


入口函数是HMaster.main(),然后再跟下去到HMasterCommandLine.run(),使用了common-cli包的读取参数,对应的参数用法:

"Usage: Master [opts] start|stop|clear\n" +
    " start  Start Master. If local mode, start Master and RegionServer in same JVM\n" +
    " stop   Start cluster shutdown; Master signals RegionServer shutdown\n" +
    " clear  Delete the master znode in ZooKeeper after a master crashes\n "+
    " where [opts] are:\n" +
    "   --minRegionServers=<servers>   Minimum RegionServers needed to host user tables.\n" +
    "   --localRegionServers=<servers> " +
      "RegionServers to start in master process when in standalone mode.\n" +
    "   --masters=<servers>            Masters to start in this process.\n" +
    "   --backup                       Master should start in backup mode";

如果参数是start,则进入startMaster()方法。这里会区分是否是本地模式,如果是本地模式,会本地启动一个ZooKeeper进程,HMaster和HRegionServer就会在同一个JVM中运行,实现在LocalHBaseCluster类里面;否则,只启动HMaster。但是不管哪种方式,都会实例化HMaster类。

在HMaster类的构造函数中会实例化ActiveMasterManager类,同时启动HBase的web console。 

  if (!conf.getBoolean("hbase.testing.nocluster", false)) {
      setInitLatch(new CountDownLatch(1));
      activeMasterManager = new ActiveMasterManager(zooKeeper, this.serverName, this);
      int infoPort = putUpJettyServer();
      startActiveMasterManager(infoPort);
    }
然后跳转到核心的方法startActiveMasterManager()

private void startActiveMasterManager(int infoPort) throws KeeperException {
    String backupZNode = ZKUtil.joinZNode(
      zooKeeper.znodePaths.backupMasterAddressesZNode, serverName.toString());
    /*
    * Add a ZNode for ourselves in the backup master directory since we
    * may not become the active master. If so, we want the actual active
    * master to know we are backup masters, so that it won't assign
    * regions to us if so configured.
    *
    * If we become the active master later, ActiveMasterManager will delete
    * this node explicitly.  If we crash before then, ZooKeeper will delete
    * this node for us since it is ephemeral.
    */
    LOG.info("Adding backup master ZNode " + backupZNode);
    if (!MasterAddressTracker.setMasterAddress(zooKeeper, backupZNode,
        serverName, infoPort)) {
      LOG.warn("Failed create of " + backupZNode + " by " + serverName);
    }

    activeMasterManager.setInfoPort(infoPort);
    // Start a thread to try to become the active master, so we won't block here
    Threads.setDaemonThreadRunning(new Thread(new Runnable() {
      @Override
      public void run() {
        int timeout = conf.getInt(HConstants.ZK_SESSION_TIMEOUT,
          HConstants.DEFAULT_ZK_SESSION_TIMEOUT);
        // If we're a backup master, stall until a primary to writes his address
        if (conf.getBoolean(HConstants.MASTER_TYPE_BACKUP,
          HConstants.DEFAULT_MASTER_TYPE_BACKUP)) {
          LOG.debug("HMaster started in backup mode. "
            + "Stalling until master znode is written.");
          // This will only be a minute or so while the cluster starts up,
          // so don't worry about setting watches on the parent znode
          while (!activeMasterManager.hasActiveMaster()) {
            LOG.debug("Waiting for master address ZNode to be written "
              + "(Also watching cluster state node)");
            Threads.sleep(timeout);
          }
        }
        MonitoredTask status = TaskMonitor.get().createStatus("Master startup");
        status.setDescription("Master startup");
        try {
          if (activeMasterManager.blockUntilBecomingActiveMaster(timeout, status)) {
            finishActiveMasterInitialization(status);
          }
        } catch (Throwable t) {
          status.setStatus("Failed to become active: " + t.getMessage());
          LOG.fatal("Failed to become active master", t);
          // HBASE-5680: Likely hadoop23 vs hadoop 20.x/1.x incompatibility
          if (t instanceof NoClassDefFoundError &&
            t.getMessage()
              .contains("org/apache/hadoop/hdfs/protocol/HdfsConstants$SafeModeAction")) {
            // improved error message for this special case
            abort("HBase is having a problem with its Hadoop jars.  You may need to "
              + "recompile HBase against Hadoop version "
              + org.apache.hadoop.util.VersionInfo.getVersion()
              + " or change your hadoop jars to start properly", t);
          } else {
            abort("Unhandled exception. Starting shutdown.", t);
          }
        } finally {
          status.cleanup();
        }
      }
    }, getServerName().toShortString() + ".activeMasterManager"));
  }

因为这里比较核心,分步骤来看

ps:这里下面所有都是包含在一个单独启动的线程中。

1)首先写入ZK,把本节点作为backup master节点,后续称为active master的时候,就删除ZK中,本节点作为backup master的纪录。

2)一直在while里面循环,知道成为active master.

3) 当成为active master的时候,调用finishActiveMasterInitilization()启动一系列组件。

3.1)MasterFileSystem类。

3.2)MasterWalManager类。

3.3)ServerManager类。管理Region Server。

3.4)TableStateManager类。管理管理表状态。

3.5)initializeZKBasedSystemTrackers()方法,初始化所有基于ZK的tracker

3.6)MasterCoprocessortHost类。为master提供协处理框架和环境。

3.7)调用startProcedureExecutor()方法。将服务停止前的wal数据再读出来,以及其他的数据清洗工作。

3.8)等待Region Server接入HMaster。不达到指定数目的Region Server连入,就一直阻塞。

3.9)启动MasterMetaBootstrap类。用于切分meta日志和分配meta表。

3.10)启动FavoredNodesManager类。

3.11)等待Region Server完成初始化。

3.12)  初始化LoadBalancer。

3.13)分配 meta region。

3.14)更新ZK中表状态。

3.15)分配meta副本

3.16)MaterQuotaManger类。负责初始化quota表在初次运行,并且提供admin接口操作quota 表