1. 程式人生 > >HBase之HRegionServer啟動(含與HMaster互動)

HBase之HRegionServer啟動(含與HMaster互動)

  在我的博文《HBase——HMaster啟動之一》、《HBase——HMaster啟動之二》中已經詳細介紹過HMaster在啟動過程中呼叫的各種方法。下面,單就HRegionServer在啟動過程中與HMaster的互動做一下深入分析。   首先,讓我們來到HRegionServer.run,由於其也是間接實現了Runnable介面。因此,在這裡,就從他的run方法開始分析。對於前面的preRegistrationInitialization方法我在這裡並不打算講,因為在我的博文《HBase——HMaster啟動之一》中已經詳細描述過。這裡,就後面的兩個方法reportForDuty、handleReportForDutyResponse進行詳細描述。   讓我們來到reportForDuty方法中。在下圖中我已經將其中的重點框選出來。其中的第一個方法是HRegionServer作為與HMaster互動的重點。我在本節將詳細講述。至於第二個方法,相信我在仔細描述第一個方法之後,大家就會感覺清晰明瞭。首先來到createRegionServerStatusStub方法。由於是長圖,所以沒有辦法編輯,還請大家諒解。   首先,來到masterAddressTracker.getMasterAddress方法。這個MasterAddressTracker在HRegionServer構造時建立並啟動,他所監聽的ZK上的路徑是/hasse/master。refresh為true,這裡強制去ZK上查詢HMaster的資訊。然後呼叫了rpcClient.createBlockingRpcChannel。這裡的rpcClient是在preRegistrationInitialization方法中構造的。
  由於在rpcClient.createBlockingRpcChannel方法中僅僅返回了新構造的BlockingRpcChannelImplementation,因此,讓我們來到BlockingRpcChannelImplementation的構造方法。這裡,我特別標明瞭BlockingRpcChannel,這個類的完整名稱是org.apache.hbase.thirdparty.com.google.protobuf.BlockingRpcChannel。這是由於hbase中將protobuf加入了其第三方包中。其真正類名應該是com.google.protobuf.BlockingRpcChannel。不論如何,他都是PB中的一個介面。這裡的BlockingRpcChannelImplementation重寫了介面中的callBlockingMethod方法,也就是說,在實際呼叫的時候,真正呼叫了rpcClient.callBlockingMethod方法。
  接著,我們回到HRegionServer.createRegionServerStatusStub方法中。由上面的那張長圖可以看到,由rpcClient.createBlockingRpcChannel返回的物件傳入了RegionServerStatusService.newBlockingStub、LockService.newBlockingStub中,構造了這兩個service的本地stub。這是PB的基礎用法,與HDFS中對於PB的使用方式不用。這裡封裝的並不是很好。接著,將這兩個service賦給HRegionServer的成員變數。   然後,我們就可以回到reportForDuty方法的第二個重點方法this.rssStub.regionServerStartup。這裡的rssStub就是剛剛構建的service。其在具體方法呼叫的時候,正是通過BlockingRpcChannelImplementation中複寫的方法來實現的。   也就是說在實際呼叫rssStub.regionServerStartup,呼叫到了AbstractRpcClient.callBlockingMethod。關於呼叫的詳細流程,我在博文《hbase之RPC呼叫流程簡介》中有簡單介紹,如果大家感覺不是很詳細,可以私信我的163郵箱
[email protected]
。我然後再寫一篇博文來詳述。這裡我們假定這個請求已經發送到了服務端。且服務端的MasterRpcServices.regionServerStartup已經開始呼叫。   接下來,我們到達HMaster端的MasterRpcServices.regionServerStartup。如下圖所示,這裡主要呼叫了ServerManager.regionServerStartup。   讓我們繼續深入ServerManager.regionServerStartup,由於其只是呼叫了ServerManager.checkAndRecordNewServer方法,並沒有其它重點內容,我在這裡就不貼圖了。而是來到ServerManager.checkAndRecordNewServer。如下圖所示。findServerWithSameHostnamePortWithLock主要是檢視當前已註冊的RegionServer中是否有同名的ServerName,如果有,則返回ServerName,如果沒有,則返回null。然後呼叫recordNewServerWithLock方法,將其ServerName放入成員變數onlineServers中,也就是說,該RegionServer已經實現了HMaster端的註冊。接著呼叫已註冊listeners的serverAdded方法,這些listeners都實現了ServerListener。主要有三個實現ServerListener介面的類:AssignmentManager、RSProcedureDispatcher、DrainingServerTracker。其中DrainingServerTracker是在其start方法中構造的匿名類。   至此,HMaster端實現與HRegionServer的第一次通訊。接著,HRegionServer開始呼叫HRegionServe.handleReportForDutyResponse方法。如下圖所示。一開始的for迴圈是為了將HMaster端返回的部分資訊新增到當前的conf成員變數中。緊接著createMyEphemeralNode方法將當前RegionServer的節點資訊寫入ZK中,路徑為/hbase/rs/~。然後呼叫ZNodeClearer.writeMyEphemeralNodeOnDisk將資訊本地化。再然後呼叫了setupWALAndReplication、startReplicationService兩個方法。由於setupWALAndReplication方法比較重要,我將在後面貼圖詳細介紹。   首先,我們來到setupWALAndReplication方法。在setupWALAndReplication方法中,主要做了兩件事情,其一是構造WALFactory,另外一個就是呼叫createNewReplicationInstance。   在構造WALFactory過程中,主要通過反射了AsyncFSWALProvider並將其封裝到SyncReplicationWALProvider中,然後呼叫其init方法。   在createNewReplicationInstance方法中主要通過反射方法建立了Replication,並呼叫了其initialize方法。並將新構建的Replication賦給了HRegionServer.replicationSourceHandler與HRegionServer.replicationSinkHandler。由於這裡的Replication比較重要,我將在下面詳細介紹。   接下來,讓我們來到Replication.initialize方法,如下圖所示。方法很長,但重點只是構造了ReplicationSourceManager。而在ReplicationSourceManager的構造方法也只是將入參封裝,並構建了一個執行緒池。   接下來,來到handleReportForDutyResponse中第二個重要也是最重要的方法startServices。這個方法很長,幾乎所有的RegionServer的服務都是直接或間接通過這個方法啟動的。   首先,我們來看initializeThreads。   這裡首先構造了MemStoreFlusher。在構造MemStoreFlusher時,值得我們注意的是,例項化了FlushHandler。接下來構例項化了CompactSplit。在構造CompactSplit的過程中,有值得我們關注的地方。下面我們跳過這張圖,來到CompactSplit的構造方法。   來到CompactSplit的構造方法以及他在構造方法中主要呼叫的兩個方法。在他的createCompactionExecutors方法中構造了一個StealJobQueue物件。這個類繼承自PriorityBlockingQueue,並且內部有一個BlockingQueue型別的stealFromQueue成員變數。然後構建了兩個執行緒池,分別以StealJobQueue、StealJobQueue.stealFromQueue為執行緒池的工作佇列。   接下來構建了一個PressureAwareCompactionThroughputController,並呼叫了其setup方法。由於其實現了Configurable介面,所以在通過ReflectionUtils.newInstance例項化的時候,呼叫了其setConf方法。在呼叫其setup時,例項化並呼叫了一個ScheduledChore物件,該物件在其複寫的chore方法中呼叫了PressureAwareCompactionThroughputController.tune。   介紹完CompactSplit的例項化後,讓我們繼續回到HRegionServer.initializeThreads方法中。在方法內,接著構造了CompactionChecker、PeriodicMemStoreFlusher這兩個ScheduledChore。接下來構造了Leases(看到這裡,你是不是很容易想到HDFS的租約系統LeaseManager)。他擴充套件了Thread而不是Chore,因為當有事情要做時,睡眠時間可以被中斷,而不是Chore睡眠時間是不變的。   緊接著,分別呼叫MovedRegionsCleaner.create、nonceManager.createCleanupScheduledChore建立了兩個ScheduledChore,在二者的chore方法中呼叫的方法分別是:regionServer.cleanMovedRegions、ServerNonceManager.cleanUpOldNonces。   然後構造了RegionServerRpcQuotaManager與RegionServerSpaceQuotaManager,最後呼叫了registerConfigurationObservers,將相關的ConfigurationObserver註冊到ConfigurationManager中。   介紹完initializeThreads方法後,讓我們回到startServices方法。   在startServices方法中接著構建了SecureBulkLoadManager並呼叫了其start方法。在其start方法中在hadoop上建立了/hbase.rootdir/staging目錄。   接著構建了LogRoller,他的作用是定期執行以確定是否應該滾動WAL。同樣,他繼承了Thread而不是Chore,因為當有事情要做時,睡眠時間可以被中斷,而不是Chore睡眠時間是不變的。   然後方法FlushThroughputControllerFactory.create的呼叫構造了NoLimitThroughputController。   接著構建了RemoteProcedureResultReporter與CompactedHFilesDischarger(繼承自ScheduledChore)。   然後呢,就像HMaster在startServiceThreads方法中一樣,建立了一大堆有不同用途的執行緒池,由ExecutorService管理(注:這裡的ExecutorService是org.apache.hadoop.hbase.executor.ExecutorService)。   緊接著,呼叫了walRoller、cacheFlusher、procedureResultReporter執行緒的start方法。這裡簡單介紹一下cacheFlusher.start。其中cacheFlusher是我們在initializeThreads方法中構造的,他的型別是MemStoreFlusher,其成員變數flushHandlers在構造期間已經完成初始化。在這裡完成了賦值與執行緒的啟動。   再然後,啟動了this.leases執行緒。構造並啟動了SplitLogWorker。   最後,分別呼叫了startHeapMemoryManager、initializeMemStoreChunkCreator。關於initializeMemStoreChunkCreator方法的呼叫,我在HMaster啟動那一節已經介紹過,這裡就略過了。需要注意的是在構建ChunkCreator時建立MemStoreChunkPool都註冊到了startHeapMemoryManager方法建立的hMemManager,也就是交由hMemManager管理。所以,這裡只是介紹startHeapMemoryManager。如下圖所示,呼叫HeapMemoryManager.create建立了HeapMemoryManager。然後呼叫HeapMemoryManager.start方法建立了HeapMemoryTunerChore並將其加入到ChoreService中呼叫。值得注意的是,在構建HeapMemoryTunerChore時,其內部的成員變數heapMemTuner型別為DefaultHeapMemoryTuner,並且,這個類實現了Configurable介面。當然他也是通過ReflectionUtils.newInstance方法建立的。   到此為止,我們已經介紹完了上面所有貼圖。下面,讓我們回到HRegionServer.run方法的後半部分。在這裡,已經接近結束了。我只是簡單介紹一下。   大家可能對這裡的rspmHost很迷惑,這個是什麼時候出現的。確實,我之前並沒有介紹過,在這裡補充一下。在HRegionServer.initializeZooKeeper方法的最後,構建了RegionServerProcedureManagerHost,並將其賦給了成員變數rspmHost。接著,便呼叫了rspmHost.loadProcedures、rspmHost.initialize。實現了他的初始呼叫。   來到最後的tryRegionServerReport,HRegionServer正是通過這個方法與HMaster保持心跳。   本節到這裡就結束了,大家有什麼不懂的地方可以私信我的郵箱[email protected]。如果感覺不錯,希望留下你的贊。你的肯定是小編繼續前進的動力。