HBase HMaster启动和停止

来源:互联网 发布:iphone屏幕检测软件 编辑:程序博客网 时间:2024/05/16 18:51
HMaster(0.90.3) Startup:

main方法: 
new HMasterCommandLine(HMaster.class).doMain(args); //args为start

HMasterCommandLine: 用于启动/停止HMaster.
doMain: 运行Tool类的run方法. 继承关系:HMasterCommandLine-->ServerCommandLine-->Tool

HMasterCommandLine.run:
1. 构造CommandLine, 基本参数有三个: minServers, backup和(start/stop)
    * minServers: 集群拥有的最少regionserver数
    * backup: 是否是backup master
    * start/stop: 启动或者停止实例
2. 如果minServers存在
    设置hbase.regions.server.count.min为minServers的指, 默认为0
3. 如果backup存在
    如果有backup参数,设置hbase.master.backup为true, 默认为false
4. 如果是start
    startMaster()
5. 如果是stop
    stopMaster()
    
startMaster:
hbase.cluster.distributed=false: 
    切换至LocalHBaseCluster(1), 启动两个JVM, 一个ZK,一个master(1)+regionserver(1).
hbase.cluster.distributed=true: 
    1. 创建一个HMaster实例, new HMaster(Configuration).
        * 获取master的地址: ip:port, 默认port为60000, 通过hbase.master.port设置
        * 获取RPC的最大handler数, 通过hbase.regionserver.handler.count设置, 默认为10.
        * 创建HMaster RPCServer实例.
        * 设置master的replication
        * 启动rpc server的服务线程, 但是当前服务还处于不可用状态
        * 修改master的mapred.task.id.(为了更好的debug log, 查看HBase MR Job运行状态)
        * 连接zookeeper, 创建相关zk node(root-region-server, unassigned, rs, table)
        * 创建master的统计类MasterMetrics
    2. HMaster.start()
        * 创建activeMasterManager对象
        * 如果hbase.master.backup设置为true, sleep直到有其他master节点创建masterZNode节点.
            Backup会一直sleep直到有其他master上线.
        * blockUntilBecomingActiveMaster: 竞争master,如果失败则阻塞直到自己成为master
            > 首先尝试创建master节点(临时节点),如果成功,自己成为master,如果失败,说明已经存在master,不管成功失败,都会在master节点上添加一个watcher.
            > 如果失败, 获取当前master的节点data, 转换为HServerAddress, 如果发现地址就是自己, 说明自己做为master刚刚重启了,删除master节点.如果不是自己, 什么也不干.
            > 同步clusterHasActiveMaster, 如果clusterHasActiveMaster.get(),则wait on clusterHasActiveMaster, 等待被notify. notify以后递归调用blockUntilBecomingActiveMaster.
                notify由handleMasterNodeChange方法触发, 一但master的zk节点有create或者delete变化,就会触发。触发后同步clusterHasActiveMaster,并notifyAll所有wait着的backup master线程.
                这里有一个有意思的地方, 如果是master自己重启, 重启以后发现zk上的master节点是自己, 然后删除节点, 这个时候会有两种情况:
                1. 删除以后,先收到watcher event, 然后同步clusterHasActiveMaster, 将clusterHasActiveMaster设置为false,notifyAll. 然后blockUntilBecomingActiveMaster进入clusterHasActiveMaster同步模块,发现clusterHasActiveMaster.get()为false, 跳过wait环节,开始递归去竞争master节点.
                2. 删除以后, 代码block部分先获得了clusterHasActiveMaster锁, 发现clusterHasActiveMaster.get()为true,则wait,释放锁, 然后收到watcher event,设置clusterHasActiveMaster为false, 在notifyAll唤醒wait.
                有意思的地方就是网络的延迟可以造成不同的执行流程, 虽然结果都一样,但是网络快的情况下,可以少一次线程切换.
                这个地方还发现有一个小bug, 就是blockUntilBecomingActiveMaster方法的返回值cleanSetOfActiveMaster, 如果是第一次进入blockUntilBecomingActiveMaster,成功成为master, 返回值为true,如果是经过一次递归以后成为master, 返回值为false. 究其原因, 是因为代码没有将递归的返回值重置给调用者. 唉..主要是这个返回值没有发挥作用,所以也没人在意吧.
                // Try to become active master again now that there is no active master
                blockUntilBecomingActiveMaster();  =递归改为=> cleanSetOfActiveMaster = blockUntilBecomingActiveMaster();
        * finishInitialization: 顾名思义就是成为master以后需要完成一些初始化工作:
            1. 创建一些master工作需要的组件:
                > MasterFileSystem: 封装了master常用的一些文件系统操作,包括split log file, 删除region目录,删除table目录,删除cf目录等,检查文件系统状态等.
                > HConnection: 创建与zk的连接.
                > ExecutorService: 维护一个ExecutorMap, 一种Event对应一个Executor(线程池). 可以提交EventHandler来执行异步事件
                > ServerManager: 管理region server信息, 维护着online region server map, 同时也维护着每个region server rpc stub.
                > CatalogTracker: 同步-ROOT-和.META.的Server地址信息.
                > AssignmentManager: 负责管理和分配region, 同时它也会接受zk上关于region的event,根据event来完成region的上下线,关闭打开等工作.
                > LoadBalancer: 负责region在region server之间的移动, 关于balancer的策略, 可以通过hbase.regions.slop来设置load区间, 下次另启一篇来深入说明下.
                > RegionServerTracker: 通过ZK的Event来跟踪online region servers, 如果有rs下线, 删除ServerManager中对应的online regions.
                > ClusterStatusTracker: 维护集群状态, 通过shutdown节点来设置集群的up或者shutdown状态.
            2. 启动集群,启动所有的服务线程: 
                > 添加shutdown节点,并设置data为master name, 表示集群启动
                > 启动ExecutorService中各个Event的Executor.
                > 启动LogCleaner: 每个60秒启动一次清除old hlogs.
                > 启动WebApp Jetty Server: 用于通过web来访问master的状态(http://host:60010/).
                > 启动RPC Server, RPC开始接受Client请求.
            3. 等待region server来签到, 看策略, 这个过程应该不会太长, 如果网络抖动很厉害, 最多集群以最少regionserver数开始服务.
                > 等待region server来签到, 每次等待1.5s, 最少等待时间4.5s, 如果online region servers到达minCount,并且在一次等待时间内没有新的server签到, 则不再等待.
                > 统计当前online region servers总共持有的region数.
            4. Split log, 分发log, 执行数据恢复
                > 获取.logs目录的log目录列表, 根据目录名和online region server的名字进行对应.
                > 如果有regionserver存在待恢复log目录, 则开始split log工作
                > Split log/recovery的流程这个可以另起一篇来讲.
            5. 分配root和meta region
                > assignRootAndMeta: 检查Root region和first meta region是否被分配了, 如果没有, 分配他们.
            6. 根据集群是启动还是故障恢复的情况来做清理工作
                > 如果当前region数为0, 表示集群是startup, 清除所有unassignment region znode, 然后扫描meta表, 重新分配所有的region.
                > 如果当前region数大于0, 表示集群是failover状态, 将处于assignment状态的节点重新assign.
            7. 启动balancer定时执行线程.
            8. 启动.META.定时扫描清理线程.
        * loop: 循环等待, 直到Stop.
stopMaster:
    Stop以后, HMaster线程结束, finally进行清理工作:
    
      stopChores(); //停止定时线程(balancer,meta清理,logCleaner)
      // Wait for all the remaining region servers to report in IFF we were
      // running a cluster shutdown AND we were NOT aborting.
      if (!this.abort && this.serverManager != null &&
          this.serverManager.isClusterShutdown()) {
        this.serverManager.letRegionServersShutdown();
      }
      stopServiceThreads();
      // Stop services started for both backup and active masters
      if (this.activeMasterManager != null) this.activeMasterManager.stop();
      if (this.catalogTracker != null) this.catalogTracker.stop();
      if (this.serverManager != null) this.serverManager.stop();
      if (this.assignmentManager != null) this.assignmentManager.stop();
      HConnectionManager.deleteConnection(this.conf, true);
      this.zooKeeper.close();