- 前记
断断续续使用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的类图如下:
入口函数是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 表