首先,讓我們來到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。
我們可以看到,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還沒有啟動,所以還沒有辦法處理。我在上面拋出的疑問也就解決了。至於以后的流程,我將在下一節詳細介紹,歡迎大家關注。
來到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的構建完成了。
