首先,让我们来到HMaster的main方法。我们今天的流程就从这里开始。
我们需要注意,下图所示的tool的类型就是HMasterCommandLine。
接下来,让我们来到HMasterCommandLine.run方法
在HMasterCommandLine.startMaster方法开始,有判断LocalHBaseCluster.isLocal(conf),也就是我们在hbase-site.xml中是否配置了hbase.cluster.distributed(默认为false)。这里我们只分析值为true的情形。其主要通过方法如下图所示:
在构建HMaster的过程中,最主要的又两个方法,其中一个是下图所示调用了其父类HRegionServer的构造方法,还有一个在下面的第二章图中有显示,也就是构建了ActiveMasterManager。其中ActiveMasterManager主要是用来处理master端与master选举相关的一切,我们简单略过。只是介绍HRegionServer的构造方法。
HRegionServer的构造方法也比较长,下面通过三张图来展示:以下分别用RSG1、RSG2、RSG3来表示。
首先我们来看RSG1中的setupNetty,如下图所示:
接下来让我们来到NettyEventLoopGroupConfig的构造方法,如下图所示,在构造方法内部,构造了Netty中的eventLoopGroup,为后面的rpc调用准备条件。
关于RSG1中的Sleeper,我们这里留一个疑问,等到HMaster真正运行的时候,他的威力才显示出来。而这个sleeper造成困扰小编很久的疑问。
接下来,让我们来到RSG2的,这是HMaster或HRegionServer在构造的重量级方法。由于我们这里只介绍HMaster,因此来到HMaster覆写的createRpcServices中,显然,在这里构建了MasterRpcServices。 我们可以看到,HMaster在构造时调用了其父类的构造方法RSRpcServices。
接下来,我们来到RSRpcServices构造方法的主体,下图将比较关键的地方框选的出来。在第一个框中,获取了即将构建的rpcServer的ip与端口(默认为16000)。在第二个框中构建了NettyRpcServer(注意,这框中的rpcSchedulerFactory其类型为SimpleRpcSchedulerFactory)。
然后,我们来到MasterRpcServices.createRpcServer,如下图所示,在这里主要构建了SimpleRpcScheduler。上面我们已经说到rpcSchedulerFactory类型为SimpleRpcSchedulerFactory。因此,在这里调用的方法是SimpleRpcSchedulertory.create。也就是调用了SimpleRpcScheduler的构造方法。由于SimpleRpcScheduler比较重要,我们在下图就略作介绍。
来到SimpleRpcScheduler的构造方法。在这里主要构建了下面三个RpcExecutor,而这三个RpcExecutor就是以后用来处理客户端请求的Executor。这里只是这三个Executor的构建,在后面的启动流程中,仍然会提到。
RpcExecutor的内容先告一段落。接下来, 让我们来到NettyRpcServer的构造方法中,由于上一步骤中使用的rpcSchedulerFactory类型为SimpleRpcSchedulerFactory,因此,这里传入的scheduler类型为SimpleRpcScheduler,也就是上面所说的。
在NettyRpcServer的构造方法中,首先调用了其父类的构造方法,其中值得留意的是将传入的scheduler保存到了成员变量中,其它初始化的内容我们这里就不赘述了。然后来到第二个框中的内容,这里的getEventLoopGroupConfig获得的对象正是HRegionServer在构造一开始调用setupNetty获得的。忘记的同学可以看看往上面翻翻。
接下来,在第三个框中,熟悉netty的同学可能就很清楚了,在这里构造了netty的服务端对象,最后,绑定了服务端端口并开始监听。
在这里需要关注下面的一个方法createNettyRpcServerPreambleHandler。在这个方法中创建了NettyRpcServerPreambleHandler,而这个handler也就是我将要在下一节介绍的完整rpc流程中服务端处理的第一个Handler。这里只是简单提一下,希望各位同学有一点印象。
看到这里,大家可以缓一口气,比较主要的服务端监听已经开始了。但是,这并不意味着HMaster就可以处理HRegionServer或客户端发送来的请求了。这里先留一个小的疑问。在后面的内容中,我将会为大家一一道来。接下来的内容依然很多,要往下读的同学需要鼓足勇气了。
上面已经为各位同学介绍了RSG2中的createRpcServices,下面简单介绍一下RSG2中的initializeFileSystem方法。在这里初始化了两个HFileSystem。
下面,来到RSG3中ZKWatcher的构造方法,如下图所示。其中,首先获取到配置中的zookeeper信息,然后封装了hbase中存储在ZK中的路径信息,接着,通过ZKUtil.connect构建了一个RecoverableZooKeeper对象,而在RecoverableZooKeeper的构造方法中创建了与ZK的连接。最后,将刚刚封装好的hbase路径在ZK上创建。
本节另外一个比较重要的方法就是RSG3中的rpcServices.start,而我在上面抛出的疑问也将在这里解答。
来到RSRpcServices.start方法,由于我并没有配置Authorization的有关信息,因此,在这里,主要调用了rpcServer.start。还记得在上面创建的rpcServer的类型吗。没错,就是在上面通过反射方式创建的NettyRpcServer。
下面,来到NettyRpcServer.start方法。有安全相关的认证在这里先跳过,直接来到scheduler.start。我相信大家可能已经忘记了这里的scheduler的类型。往上面翻一翻就可以知道,这里的scheduler类型为SimpleRpcScheduler。
来到SimpleRpcScheduler.start。各位同学时候还记得在这里的各个executor的类型,没错,他们的类型都是FastPathBalancedQueueRpcExecutor,下面我就分析一下其中start的奥秘。下面所框选的内容都比较关键,有余力的同学可以看一下,在后面的章节中我也会提到。 这里的RpcExecutor实际类型为FastPathBalancedQueueRpcExecutor。
因而,来到FastPathBalancedQueueRpcExecutor,可以看到,返回的对象类型为FastPathHandler。在构造好FastPathHandler对象之后,调用了start方法。FastPathHandler继承自Handler。再往下看。 来到Handler类,看到其继承自Thread,并且覆写了Thread的run方法。也就是说,在上面调用start方法的时候,这里的run方法开始运行。由于Handler的实际类型为FastPathHandler,因此,在真正运行时,下图调用的getCallRunner为FastPathHandler.getCallRunner。比较关心的同学可以自己看一下。在这一节重点并不是这里,就点到为止了。 到现在为止,rpcServices的启动完成了,并且HMaster就可以处理HRegionServer或客户端发送来的请求了。各位同学可能还不清楚为什么。我在这里通过下面的图来简单介绍一下。客户端请求到服务端后,来到这里,将通过调用scheduler.dispatch,这里的sceduler也就是我在前面提到的SimpleRpcScheduler。由于刚刚handler已经启动完成,所有dispath后的所有请求,都可以由handler处理,而在上面,handler还没有启动,所以还没有办法处理。我在上面抛出的疑问也就解决了。至于以后的流程,我将在下一节详细介绍,欢迎大家关注。
在RSG3中,然后创建了ChoreService。很多同学可能会对ChoreService不太清楚。其实ChoreService就是对很多继承自ScheduledChore的周期性调用。在ChoreService内部有一个周期性调度线程池ScheduledThreadPoolExecutor。在实例化时其真正类型一般是JitterScheduledThreadPoolExecutorImpl。而ScheduledChore是通过ChoreService调度激活的任务。ScheduledChore在ChoreService中调度运行时会与ChoreService中其他ScheduledChores竞争访问ChoreService线程池中的线程。
接着创建了ExecutorService,注意这里的并非java中的ExecutorService,而是org.apache.hadoop.hbase.executor.ExecutorService。后面在HMaster调用startServiceThreads时会用到。
到此,HMaster的构建完成了。