HBASE关闭集群流程浅析

作者:破碎虚空圳

【引言】

          我们偶尔进行关闭HBASE集群的时候,在$HBASE_HOME/bin/stop-hbase.sh执行后,会打印无数行......................................,有时候会执行2个小时,也无法关闭。执行jps后发现master和少部分regionserver依然在运行,什么原因会导致一个无限的等待呢?(注意,本文所指HBASE版本0.90 cdh3,不适用于其他版本)。下面让我们进行一个HBASE关闭集群的浅析,来揭开这个谜底。

【正文】

         在HMaster.java的开头注释中,清晰的说明了关闭整个集群可以通过调用shutdown(),先通知所有的regionserver去关闭,然后等待所有的regionserver返回他们关闭的消息,最后Master关闭自身。    

* 

The Master can be asked shutdown the cluster. See {@link #shutdown()}. In * this case it will tell all regionservers to go down and then wait on them * all reporting in that they are down. This master will then shut itself down.

下面从shutdown()开始分析:
  @Override
  public void shutdown() {
    this.serverManager.shutdownCluster();
    try {
      this.clusterStatusTracker.setClusterDown();
    } catch (KeeperException e) {
      LOG.error("ZooKeeper exception trying to set cluster as down in ZK", e);
    }
  }

ServerManager是管理和维护所有RegionServer信息的类(包括online和dead)。

public void shutdownCluster() {
    this.clusterShutdown = true;
    this.master.stop("Cluster shutdown requested");
  }
在这一段代码中
this.master.stop("Cluster shutdown requested");
会让HMaster主线程中的变量this.stopped 为true。这会引起主线程(run())中的loop()循环退出。进而执行finally下的内容。

其中

 this.serverManager.letRegionServersShutdown();

不进行任何操作,只是等待所有的RegionServer去关闭。

 void letRegionServersShutdown() {
    synchronized (onlineServers) {
      while (onlineServers.size() > 0) {
        StringBuilder sb = new StringBuilder();
        for (String key: this.onlineServers.keySet()) {
          if (sb.length() > 0) {
            sb.append(", ");
          }
          sb.append(key);
        }
        LOG.info("Waiting on regionserver(s) to go down " + sb.toString());
        try {
          this.onlineServers.wait(1000);
        } catch (InterruptedException e) {
          // continue
        }
那么真正发送关闭RegionServer的地方在哪儿?找了一圈,结果发现没有任何一个地方出现HMASTER主动让REGIONSERVER关闭的代码或接口。真正的原因是HMASTER与REGIONSER的心跳主动的发起者永远是REGIONSERVER。当REGIONSER在某个期限(hbase.regionserver.msginterval配置,默认3*1000)后,向HMASTER发起心跳的时候,HMASTER会将当前需要关闭的指令(HMSG)返回给REGIONSERVER。

 @Override

  public HMsg [] regionServerReport(HServerInfo serverInfo, HMsg msgs[],
    HRegionInfo[] mostLoadedRegions)
  throws IOException {
    return adornRegionServerAnswer(serverInfo,
      this.serverManager.regionServerReport(serverInfo, msgs, mostLoadedRegions));
  }
在ServerManager的regionServerReport方法中:
if (this.clusterShutdown) {
      if (numservers <= 2) {
        // Shutdown needs to be staggered; the meta regions need to close last
        // in case they need to be updated during the close melee.  If <= 2
        // servers left, then these are the two that were carrying root and meta
        // most likely (TODO: This presumes unsplittable meta -- FIX). Tell
        // these servers can shutdown now too.
        reply = HMsg.STOP_REGIONSERVER_ARRAY;
      }
    }
这样子RegionServer通过RPC发送心跳的时候,就会收到STOP_REGIONSERVER_ARRAY的指示,去关闭自己。

RegionServer是在其主线程的run方法中,定时发送心跳

tryRegionServerReport(outboundMessages);
在上述方法中,出现如下代码
if (msgs[i].getType().equals(HMsg.Type.STOP_REGIONSERVER)) {
        stop("Received " + msgs[i]);
        continue;
      }
这里有一个疑问,RegionServer是如何最后一次发心跳的?因为RegionServer主线程中循环心跳的条件是
for (int tries = 0; !this.stopped && isHealthy();) {
但最后已经是stopped=为true了。也就是说,临时的时候,还会再发送一次心跳吗?

通过研究后,发现真正的地方是在RegionServerTracker这个类中,此类会一直监控Zookeeper的/hbase/rs目录,如果某个RegionServer关闭了,则Zookeeper上的/hbase/rs会delete一个,则RegionServerTracker会删除一个Regionserver节点。

@Override
  public void nodeDeleted(String path) {
    if (path.startsWith(watcher.rsZNode)) {
      String serverName = ZKUtil.getNodeName(path);
      LOG.info("RegionServer ephemeral node deleted, processing expiration [" +
        serverName + "]");
      ServerName sn = ServerName.parseServerName(serverName);
      if (!serverManager.isServerOnline(sn)) {
        LOG.info(serverName.toString() + " is not online");
        return;
      }
      remove(sn);
      this.serverManager.expireServer(sn);
    }
  }
其是,通过ServerManager来删除了
private final Map serverConnections = new HashMap();
这样执行 letRegionServersShutdown()就会最终退出。

如果一直关闭不了的条件如下:

1.在Zookeeper 的/hbase/rs中的节点始终存在。

2(.RegionServer不能向HMaster发送心跳,导致其无法接受关闭命令)或(接受了关闭了命令,但此RegionServer无法关闭)。

所以,当关闭不了的时候,要查询具体原因,可以先看ZOOKEEPER上的/hbase/rs上,还存在哪个RegionServer,然后查看此RegionServer的日志,查询具体的原因。

你可能感兴趣的:(HBASE关闭集群流程浅析)