HBase 1.2.0源码分析:HMaster启动

HMaster 启动类org.apache.hadoop.hbase.master.HMaster,HMaster 继承了 HRegionServer,实现了 MasterServices。

类描述:HMaster 可以运行多个,通过 Zookeeper 选出一个 Active Master,其他 HMaster 会阻塞在构造方法中,直到集群 shutdown 或 active master 丢失(An HBase cluster has one active master. If many masters are started, all compete. Whichever wins goes on to run the cluster. All others park themselves in their constructor until master or cluster shutdown or until the active master loses its lease in zookeeper


0. HMaster 初始化

a. 初始化以下信息:
fatal error 缓存、Replication 信息、 压缩和加密信息(HBASE-6370)、HMaster 指标监控、表描述符(默认预加载)
b. 服务状态的推送(默认不开启),hbase.status.publisher.class指定发布实现类
c. 启动内嵌的 JettyServer,默认监听"0.0.0.0:16010"端口,可以通过 web 的方式访问 master 的信息
d. 启动 ActiveMasterManager,连接ZK进行 Master 选举,如果不是 Master 的话,就一直阻塞。

public HMaster(final Configuration conf, CoordinatedStateManager csm)
      throws IOException, KeeperException, InterruptedException {
    super(conf, csm);
    // 存放来自 region server 的 fatal error 信息,超过 buffer 大小后会自动清理。
    this.rsFatals = new MemoryBoundedLogMessageBuffer(
      conf.getLong("hbase.master.buffer.for.rs.fatals", 1*1024*1024));

    // Disable usage of meta replicas in the master
    this.conf.setBoolean(HConstants.USE_META_REPLICAS, false);
    
    // 初始化 Replication 信息
    Replication.decorateMasterConfiguration(this.conf);
    
    // 初始化 HMaster 的压缩和加密信息
    this.masterCheckCompression = conf.getBoolean("hbase.master.check.compression", true);
    this.masterCheckEncryption = conf.getBoolean("hbase.master.check.encryption", true);

    // Metrics for HMaster
    this.metricsMaster = new MetricsMaster(new MetricsMasterWrapperImpl(this));

    // 预加载表 Schema
    this.preLoadTableDescriptors = conf.getBoolean("hbase.master.preload.tabledescriptors", true);

    // ..
    
    // ZK监控
    activeMasterManager = new ActiveMasterManager(zooKeeper, this.serverName, this);
    // 启动内嵌的 JettyServer,默认监听"0.0.0.0:16010"端口,可以通过 web 的方式访问 HMaster 的信息
    int infoPort = putUpJettyServer();
    // 选举 Master
    startActiveMasterManager(infoPort);
    
  }

1. 选举成为 Master 后会调用finishActiveMasterInitialization

创建监控HMaster线程(InitializationMonitor),初始化以下对象或操作:

private void finishActiveMasterInitialization(MonitoredTask status)
      throws IOException, InterruptedException, KeeperException, CoordinatedStateException {
    isActiveMaster = true;
    
    // 监控线程
    Thread zombieDetector = new Thread(new InitializationMonitor(this));
    zombieDetector.start();
    
    // 包装 HDFS 操作
    this.fileSystemManager = new MasterFileSystem(this, this);
    
    // 设置 Meta 表的 Replication
    this.tableDescriptors.get(TableName.META_TABLE_NAME)
        .setRegionReplication(
            conf.getInt(HConstants.META_REPLICAS_NUM, HConstants.DEFAULT_META_REPLICA_NUM));
            
    // 加载表 Schema 信息,从 HDFS 上读取        
    if (preLoadTableDescriptors) {
        this.tableDescriptors.getAll();
    }
    
    // 创建 ServerManager,管理 Region Server
    this.serverManager = createServerManager(this, this);
    
    // 提供访问集群里所有 Server 的方式
    setupClusterConnection();
    
    // 清楚表级别的 Write lock
    this.tableLockManager.reapWriteLocks();
    
    // 初始化一系列监控ZK的对象,详细见下文
    initializeZKBasedSystemTrackers();
    
    // 在处理请求前,初始化 master side coprocessors
    // 提供Coprocessor的运行环境
    this.cpHost = new MasterCoprocessorHost(this, this.conf);
    
    // 启动 HMaster 处理任务的线程池
    // MASTER_CLOSE_REGION           hbase.master.executor.openregion.threads
    // MASTER_OPEN_REGION            hbase.master.executor.closeregion.threads
    // MASTER_SERVER_OPERATIONS      hbase.master.executor.serverops.threads
    // MASTER_META_SERVER_OPERATIONS hbase.master.executor.serverops.threads
    // M_LOG_REPLAY_OPS              hbase.master.executor.logreplayops.threads
    // MASTER_TABLE_OPERATIONS       1
    startServiceThreads();
    
    // 等待 RegionServer 的汇报
    // 1. 向 HMaster 汇报的 RegionServer 数量达到hbase.master.wait.on.regionservers.maxtostart(Integer.MAX_VALUE)
    // 2. 向 HMaster 汇报的 RegionRerver 数量达到hbase.master.wait.on.regionservers.mintostart(1),
    //    并且等待时间超过hbase.master.wait.on.regionservers.timeout(4500ms)
    //    同时在hbase.master.wait.on.regionservers.interval(1500ms)内向 HMaster 注册的 RegionServer 数量没有变
    // 在同时满足以上条件后结束等待
    this.serverManager.waitForRegionServers(status);
    
    // 检查在ZK当中注册了,但是没在 HMaster 这里注册的 RegionServer
    for (ServerName sn: this.regionServerTracker.getOnlineServers()) {
        // 只输出日志,不处理
    }
    
    // ... 分配Meta Region
}

1.1 initializeZKBasedSystemTrackers创建以下对象:

// RegionServer region balancer,控制 RegionServer 负载
// 返回 RegionPlan(Region 应该放在哪个 RegionServer 上)
// 默认为 StochasticLoadBalancer
this.balancer = LoadBalancerFactory.getLoadBalancer(conf);

// 用于 Region 的 split 和 merge 使得一个 table 的所有 region 的大小趋于均衡
// 默认为 SimpleRegionNormalizer
this.normalizer = RegionNormalizerFactory.getRegionNormalizer(conf);

// 监听 load balancer 状态
// ZK节点 /hbase/balancer(zookeeper.znode.balancer)
this.loadBalancerTracker = new LoadBalancerTracker(zooKeeper, this);

// 监听 region normalizer 状态
// ZK节点 /hbase/normalizer(zookeeper.znode.regionNormalizer)
this.regionNormalizerTracker = new RegionNormalizerTracker(zooKeeper, this);

// 负责 Assign Region,RPC通知 RegionServer 执行 open region 操作
// 这里能找到 RIT 的 Region
// 监听 /hbase/region-in-transition 节点(zookeeper.znode.unassigned)
this.assignmentManager = new AssignmentManager(this, serverManager,
      this.balancer, this.service, this.metricsMaster,
      this.tableLockManager);

// 监听 RegionServer 的状态
// ZK节点 /hbase/rs(zookeeper.znode.rs)
this.regionServerTracker = new RegionServerTracker(zooKeeper, this,
        this.serverManager);

// 监听 RegionServer(下线的) 的状态
// ZK节点 /hbase/draining(zookeeper.znode.draining.rs)
this.drainingServerTracker = new DrainingServerTracker(zooKeeper, this,
      this.serverManager);

// 监听 cluster 是否正常运行
// ZK节点 /hbase/running(zookeeper.znode.state)的内容为当前 HMaster 的信息
boolean wasUp = this.clusterStatusTracker.isClusterUp();
if (!wasUp) this.clusterStatusTracker.setClusterUp();

// 注册 SnapshotManager、MasterFlushTableProcedureManager 和其他ProcedureManager
// Procedure 负责处理对 Table 的创建、修改、Flush 等操作
// mpmHost 提供 Procedure 的运行环境
this.snapshotManager = new SnapshotManager();
this.mpmHost = new MasterProcedureManagerHost();
this.mpmHost.register(this.snapshotManager);
this.mpmHost.register(new MasterFlushTableProcedureManager());
this.mpmHost.loadProcedures(conf);

2. 在第一步操作完,初始化了各种对象后,需要分配 META 表

在此之前,恢复 Meta 表,对 failed server 上的 meta region 执行 split

private void finishActiveMasterInitialization(MonitoredTask status)
      throws IOException, InterruptedException, KeeperException, CoordinatedStateException {
      
    // ...
    
    // 注释:在 Master 启动过程中会恢复 meta region server
    // 其他失败的 rs 建议通过 SSH 处理会尽可能快速启动 Master
    
    // 从 WALs 目录下找出之前失败或的RS
    // HDFS 目录 /hbase/WALs 下每一个 RegionServer 有一个子目录,从 /hbase/WALs 中解析出所有的RS,不在 onlineServers 中的即认为是失败的。
    Set<ServerName> previouslyFailedServers =
          this.fileSystemManager.getFailedServersFromLogFolders();
    
    // log splitting for hbase:meta server
    // 获得 meta region 所在的 RegionServer
    // ZK节点 /hbase/meta-region-server 存储之前 meta region 所在的 server
    ServerName oldMetaServerLocation = metaTableLocator.getMetaRegionLocation(this.getZooKeeper());
    // 如果之前 meta region 所在的 server 在 failed server 列表中,则认为 meta region 需要恢复
    if (oldMetaServerLocation != null && previouslyFailedServers.contains(oldMetaServerLocation)) {
        // 执行 split meta log
        splitMetaLogBeforeAssignment(oldMetaServerLocation);
    }
    
    // ...
}

private void splitMetaLogBeforeAssignment(ServerName currentMetaServer)
      throws IOException {
      
    // hbase.master.distributed.log.replay 属性,默认是 false,即 log split
    // RecoveryMode 是 LOG_REPLAY(日志重放),将 meta region 放到ZK的 /hbase/recovering-regions下
    if (RecoveryMode.LOG_REPLAY == this.getMasterFileSystem().getLogRecoveryMode()) {
      Set<HRegionInfo> regions = new HashSet<HRegionInfo>();
      regions.add(HRegionInfo.FIRST_META_REGIONINFO);
      this.fileSystemManager.prepareLogReplay(currentMetaServer, regions);
    } 
    
    // RecoveryMode 是 LOG_SPLITTING(日志切分)的 meta region 所在的failed region server 的 WAL log 做 split log 操作
    else {
      this.fileSystemManager.splitMetaLog(currentMetaServer);
    }
}


2.1 调用 splitLog 方法执行 split 日志的操作

public void splitLog(final Set<ServerName> serverNames, PathFilter filter) 
      throws IOException {
    long splitTime = 0, splitLogSize = 0;
    // 修改 WALs 日志目录的名称,在需要 split 的目录的名称后面加上.splitting
    List<Path> logDirs = getLogDirs(serverNames);

    // splitLogManager 记录 dead server 列表
    splitLogManager.handleDeadWorkers(serverNames);
    
    // 执行 split 日志
    splitLogSize = splitLogManager.splitLogDistributed(serverNames, logDirs, filter);
    
    // 记录 split 结果到 MetricsMaster 当中
    // 使用 path filter 区分 META 表和普通表,META 表的日志以.meta结尾
    if (this.metricsMasterFilesystem != null) {
      if (filter == META_FILTER) {
        this.metricsMasterFilesystem.addMetaWALSplit(splitTime, splitLogSize);
      } else {
        this.metricsMasterFilesystem.addSplit(splitTime, splitLogSize);
      }
    }
}

/**
 * 执行 Split log
 * 在所有指定 region server 的 META 表日志处理结束(成功或失败)前阻塞
 * @param logDirs List of log dirs to split
 * @param filter the Path filter to select specific files for considering
 * @return cumulative size of the logfiles split
*/
public long splitLogDistributed(final Set<ServerName> serverNames, final List<Path> logDirs,
      PathFilter filter) throws IOException {
    
    FileStatus[] logfiles = getFileList(logDirs, filter);
    
    // ...
    
    // 统计任务完成结果
    TaskBatch batch = new TaskBatch();
    Boolean isMetaRecovery = (filter == null) ? null : false;
    for (FileStatus lf : logfiles) {
        String pathToLog = FSUtils.removeRootPath(lf.getPath(), conf);
      
        // 把任务插入到 Split 任务列表当中
        // 在ZK节点 /hbase/splitWAL下创建原来的相对路径名加密编码后的值
        if (!enqueueSplitTask(pathToLog, batch)) {
            throw new IOException("duplicate log split scheduled for " + lf.getPath());
        }
    }
    
    // 等待任务结束
    // RegionServer 会有 SplitLogWorker 读取ZK节点 /hbase/splitWAL 处理 Split
    // 参考 SplitLogWorker.splitLogFile
    waitForSplittingCompletion(batch, status);
    
    // remove recovering regions
    if (filter == MasterFileSystem.META_FILTER) {
      isMetaRecovery = true;
    }
    // 清理 recovering 的状态
    // region server 不让访问 recovering 状态的 region
    removeRecoveringRegions(serverNames, isMetaRecovery);

    if (batch.done != batch.installed) {
        // 启动的任务和完成的任务不相等的情况
        // ... 记录异常
        throw new IOException(msg);
    }
    
    // 清理 Split 前的log文件
    for (Path logDir : logDirs) {
        
        final FileSystem fs = logDir.getFileSystem(conf);
        try {
            if (fs.exists(logDir) && !fs.delete(logDir, false)) {
                LOG.warn("Unable to delete log src dir. Ignoring. " + logDir);
            }
        } catch (IOException ioe) {
            // ...
      }
    }
    
    return totalSize;
}

2.2 分配 Meta 表,调用assignMeta

void assignMeta(MonitoredTask status, Set<ServerName> previouslyFailedMetaRSs, int replicaId)
      throws InterruptedException, IOException, KeeperException {
    // Work on meta region
    int assigned = 0;
    
    RegionStates regionStates = assignmentManager.getRegionStates();
    // 从ZK节点 /hbase/meta-region-server 获取当前 meta state
    RegionState metaState = MetaTableLocator.getMetaRegionState(getZooKeeper(), replicaId);
    
    // meta 表第一个 region
    HRegionInfo hri = RegionReplicaUtil.getRegionInfoForReplica(HRegionInfo.FIRST_META_REGIONINFO,
        replicaId);
    ServerName currentMetaServer = metaState.getServerName();
    
    // Add a region to RegionStates
    if (!ConfigUtil.useZKForAssignment(conf)) {
      regionStates.createRegionState(hri, metaState.getState(),
        currentMetaServer, null);
    } else {
      regionStates.createRegionState(hri);
    }
    
    // If region is up in zk in transition, then do fixup and block and wait until 
    // the region is assigned and out of transition. 
    // 处理 meta 表第一个 region
    boolean rit = this.assignmentManager.
      processRegionInTransitionAndBlockUntilAssigned(hri);
    // 在 timeout 时间内等待 hbase:meta 表是否可以被访问  
    boolean metaRegionLocation = metaTableLocator.verifyMetaRegionLocation(
      this.getConnection(), this.getZooKeeper(), timeout, replicaId);
      
    if (!metaRegionLocation || !metaState.isOpened()) {
        // Meta location is not verified. It should be in transition, or offline.
        // We will wait for it to be assigned in enableSSHandWaitForMeta below.
        if (!ConfigUtil.useZKForAssignment(conf)) {
            assignMetaZkLess(regionStates, metaState, timeout, previouslyFailedMetaRSs);
        } else if (!rit) {
            // 重新执行之前的 Split log 操作
            if (currentMetaServer != null) {
                if (serverManager.isServerOnline(currentMetaServer)) {
                    serverManager.expireServer(currentMetaServer);
                }
                if (replicaId == HRegionInfo.DEFAULT_REPLICA_ID) {
                    splitMetaLogBeforeAssignment(currentMetaServer);
                    previouslyFailedMetaRSs.add(currentMetaServer);
                }
            }
            
            // 重新 assign 一次 meta 表
            assignmentManager.assignMeta(hri);
        }
    } 
    
    else {
        // assign 成功,更新状态为 online
        regionStates.updateRegionState(
            HRegionInfo.FIRST_META_REGIONINFO, State.OPEN, currentMetaServer);
        this.assignmentManager.regionOnline(
            HRegionInfo.FIRST_META_REGIONINFO, currentMetaServer);
    }

    // ZK中设置 meta 表启用状态
    if (replicaId == HRegionInfo.DEFAULT_REPLICA_ID) enableMeta(TableName.META_TABLE_NAME);

    // ...

}

在 AssignmentManager 中调用assign,向 RegionServer 发请求 open region

regionOpenState = serverManager.sendRegionOpen(
              plan.getDestination(), region, versionOfOfflineNode, favoredNodes);

3. 恢复其他 region

回到finishActiveMasterInitialization方法中,对 dead server 进行处理

// previouslyFailedServers 是之前判断出来的 dead server
for (ServerName tmpServer : previouslyFailedServers) {
    // 将这些 server 保存起来,master 不会等待他们都恢复完再继续
    this.serverManager.processDeadServer(tmpServer, true);
}

恢复这些 region 的过程比较慢,涉及到 WAL log split 和 region assign,HMaster 不会等待他们恢复

分配 region 的工作都是由 assignmentManager 来完成的,调用assignmentManager.joinCluster()

// 如果是新启动的,就分配所有的用户 region
// 如果是 failover 的情况,就修复 assignmentManager 当中有问题的 region 状态,
void joinCluster() throws IOException,
      KeeperException, InterruptedException, CoordinatedStateException {
    long startTime = System.currentTimeMillis();
    
    // 获得 dead server 列表
    // Scan hbase:meta 表构建 region、server和 assignment 列表
    // replicasToClose 保存需要重新 assign 的 region(merge 和 split 状态的region)
    // offlineServers 保存 dead server(region 所在 server 不在 onlineServer)
    Set<ServerName> deadServers = rebuildUserRegions();
    
    // 处理 deadServer 和正在 merge 或 transition 没有完成的 region
    // 在方法里要判断是否是 failover 的情况
    boolean failover = processDeadServersAndRegionsInTransition(deadServers);

    // 清除ZK节点 /hbase/region-in-transition(zookeeper.znode.unassigned)
    if (!useZKForAssignment) {
      ZKUtil.deleteNodeRecursively(watcher, watcher.assignmentZNode);
    }
    
    // 恢复在 Enabling 和 Disabling 状态的表
    recoverTableInDisablingState();
    recoverTableInEnablingState();
}

3.1 processDeadServersAndRegionsInTransition方法

主要逻辑用于判断是否是 failover

// Process all regions that are in transition in zookeeper and also 
// processes the list of dead servers.
boolean processDeadServersAndRegionsInTransition(final Set<ServerName> deadServers)
      throws KeeperException, IOException, InterruptedException, CoordinatedStateException {

    // 读ZK的节点 /hbase/region-in-transition 获取需要 assignment 的 region
    List<String> nodes = ZKUtil.listChildrenNoWatch(watcher, watcher.assignmentZNode);

    // serverManager 里有 deadServer
    boolean failover = !serverManager.getDeadServers().isEmpty();
    if (failover) {
        // ...
    } else {
        // 如果除了 meta region 外有 region 是 assigned 状态,是 failover
        Set<ServerName> onlineServers = serverManager.getOnlineServers().keySet();
        for (Map.Entry<HRegionInfo, ServerName> en:
          regionStates.getRegionAssignments().entrySet()) {
            HRegionInfo hri = en.getKey();
            if (!hri.isMetaTable()
                && onlineServers.contains(en.getValue())) {
                failover = true;
                break;
            }
        }
        if (!failover && nodes != null) {
            // 如果除了 meta region 外有 region 是 RIT 状态(有 split 或者 merge 还没有完成的 region)是 failover
            for (String encodedName: nodes) {
                RegionState regionState = regionStates.getRegionState(encodedName);
                if (regionState != null && !regionState.getRegion().isMetaRegion()) {
                    failover = true;
                    break;
                }
            }
        }
    }
    
    if (!failover && !useZKForAssignment) {
        // 如果除了 meta region 外有 region 是 RIT 状态(有 split 或者 merge 还没有完成的 region)是 failover
        Map<String, RegionState> regionsInTransition = regionStates.getRegionsInTransition();
        if (!regionsInTransition.isEmpty()) {
            Set<ServerName> onlineServers = serverManager.getOnlineServers().keySet();
            for (RegionState regionState: regionsInTransition.values()) {
                ServerName serverName = regionState.getServerName();
                if (!regionState.getRegion().isMetaRegion()
                        && serverName != null && onlineServers.contains(serverName)) {
                    failover = true;
                    break;
                }
            }
        }
    }
    
    if (!failover) {
        // 如果 dead server 的 WALs 路径下有 splitting log,是 failover
        Set<ServerName> queuedDeadServers = serverManager.getRequeuedDeadServers().keySet();
        if (!queuedDeadServers.isEmpty()) {
            // ...
            for (ServerName serverName: queuedDeadServers) {
                // ...
                Path splitDir = logDir.suffix(DefaultWALProvider.SPLITTING_EXT);
                if (fs.exists(logDir) || fs.exists(splitDir)) {
                    failover = true;
                    break;
                }
            }
            
            if (!failover) {
                // 如果不是 failover,清除 dead server
                serverManager.removeRequeuedDeadServers();
            }
        }
    }

    Set<TableName> disabledOrDisablingOrEnabling = null;
    Map<HRegionInfo, ServerName> allRegions = null;

    if (!failover) {
        disabledOrDisablingOrEnabling = tableStateManager.getTablesInStates(
          ZooKeeperProtos.Table.State.DISABLED,
          ZooKeeperProtos.Table.State.DISABLING,
          ZooKeeperProtos.Table.State.ENABLING);

        // mark all user regions closed before reassignment
        allRegions = regionStates.closeAllUserRegions(
        disabledOrDisablingOrEnabling);
    }

    // Now region states are restored
    regionStateStore.start();

    if (failover) {
        // 如果是 failover,处理 dead server 和 RIT
        // dead server 通过 ServerCrashProcedure 异步完成
        // region in transition 同步完成
        // See HBASE-4580 for more information.
        processDeadServersAndRecoverLostRegions(deadServers);
    }

    if (!failover && useZKForAssignment) {
        // 清除ZK监听,并启动新的监听
        ZKAssign.deleteAllNodes(watcher);
        ZKUtil.listChildrenAndWatchForNewChildren(this.watcher,
            this.watcher.assignmentZNode);
    }

    if (!failover) {
        // assign 所有的 regions
        assignAllUserRegions(allRegions);
    }
    
    // ...
}

3.2 异步 assign region

private void assign(int regions, int totalServers,
      String message, Map<ServerName, List<HRegionInfo>> bulkPlan)
          throws InterruptedException, IOException {

    int servers = bulkPlan.size();
    
    // hbase.bulk.assignment.threshold.regions
    // hbase.bulk.assignment.threshold.servers
    // 如果 region 数量或着 server 数量超过阈值,使用 bulk assign
    if (servers == 1 || (regions < bulkAssignThresholdRegions
        && servers < bulkAssignThresholdServers)) {
        // 小集群下效率更高
        ArrayList<HRegionInfo> userRegionSet = new ArrayList<HRegionInfo>(regions);
        for (Map.Entry<ServerName, List<HRegionInfo>> plan: bulkPlan.entrySet()) {
            if (!assign(plan.getKey(), plan.getValue())) {
                for (HRegionInfo region: plan.getValue()) {
                    if (!regionStates.isRegionOnline(region)) {
                        // 异步 assign
                        // 线程池中调用 assignmentManager.assign(hri, true, newPlan);
                        // 线程池大小 hbase.assignment.threads.max,默认30
                        invokeAssign(region);
                    }
                }
            }
        }

        // 等待 assignment 完成
        // 等待时间 hbase.bulk.assignment.perregion.open.time * (reassigningRegions + 1)
        if (!waitForAssignment(userRegionSet, true, userRegionSet.size(),
            System.currentTimeMillis())) {
            // ....
        }
        
    } else {
        // bulk assign
        // 使用 fixed 线程池 assign
        BulkAssigner ba = new GeneralBulkAssigner(
          this.server, bulkPlan, this, bulkAssignWaitTillAllAssigned);
        ba.bulkAssign();
    }
}

分配用户 region 的方法和分配 meta 的过程基本一致。

4. 开启一系列调度,由 choreService 执行

// master.getClusterStatus()
// 获取 clusterStatus,用于 loadBalancer 决定 assign region 到哪个 server 上
this.clusterStatusChore = new ClusterStatusChore(this, balancer);
getChoreService().scheduleChore(clusterStatusChore);

// master.balance()
// 获得 RegionPlan(需要移动的 region info,source region server 和 dest region server)
// 只负责根据 clusterStatus 生成 RegionPlan,region 的迁移则是由 assignmentManager 根据 plan 完成
this.balancerChore = new BalancerChore(this);
getChoreService().scheduleChore(balancerChore);

// master.normalizeRegions()
// 使得一个 table 的所有 region 的大小趋于均衡
// split 过大的 region,merge 太小的 region
// 生成 NormalizationPlan(SplitNormalizationPlan、MergeNormalizationPlan、EmptyNormalizationPlan)
// AdminService 会发送 RPC 到某个 region server 让其对 region split 或者 merge
this.normalizerChore = new RegionNormalizerChore(this);
getChoreService().scheduleChore(normalizerChore);


// 对于被 merge 或 split 操作成为新 region
// 定期 scan meta table,如果新 region 不在持有旧 region 的 reference file
// 可以移除旧 region(HFile 移动到 HDFS 目录 /hbase/archive/{tableName}/{encoded-region-name} 路径下)
this.catalogJanitorChore = new CatalogJanitor(this, this);
getChoreService().scheduleChore(catalogJanitorChore);

5. 其他操作

// 创建 TableNamespaceManager,创建、访问、操作 namespace 的包装类
initNamespace();

// 创建 MasterQuotaManager,创建、访问、操作 quota 的包装类
initQuotaManager();

// 清除与 online server 有相同 host name 和 port 的dead server
// See HBASE-5916.
this.serverManager.clearDeadServersWithSameHostNameAndPortOfOnlineServer();
    
// Check and set the znode ACLs if needed in case we are overtaking a non-secure configuration
zooKeeper.checkAndSetZNodeAcls();
...

HMaster的主要启动流程如上所诉。欢迎补充和提出错误。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容

  • 本文基于hbase-1.3.0源码 1. HMaster启动 HMaster继承了HRegionServer,实现...
    aaron1993阅读 4,829评论 2 5
  • 简介 HBase是高可靠性,高性能,面向列,可伸缩的分布式存储系统,利用HBase技术可在廉价PC Serve...
    九世的猫阅读 2,192评论 1 6
  • 本文首先简单介绍了HBase,然后重点讲述了HBase的高并发和实时处理数据 、HBase数据模型、HBase物理...
    达微阅读 2,734评论 1 13
  • HBase Architectural Components(HBase架构组件) HBase架构也是主从架构,由...
    陌上疏影凉阅读 2,397评论 0 7
  • 参考:https://www.jianshu.com/p/569106a3008f 最近在逐步跟进Hbase的相关...
    博弈史密斯阅读 855评论 1 1