天天看點

HBase源碼:HMaster啟動過程調試HMastermain方法HMaster類圖HMaster的構造方法run方法MasterFileSystem構造方法總結

版本:hbase 0.94.15-cdh4.7.0

說明:

首先,在ide裡啟動hmaster和hregionserver:

運作<code>/hbase/src/test/java/my/test/start/hmasterstarter.java</code>,當看到提示<code>waiting for region servers count to settle</code>時, 再打開同目錄中的hregionserverstarter,統一運作該類。

此時會有兩個console,在hmasterstarter這個console最後出現<code>master has completed initialization</code>,這樣的資訊時就表示它啟動成功了,而hregionserverstarter這個console最後出現<code>done with post open deploy task</code>這樣的資訊時說明它啟動成功了。

運作hmasterstarter類啟動hmaster:

hmaster的入口是main方法,main方法需要傳遞一個參數,start或者stop。

main方法内首先列印hbase版本資訊,然後在調用hmastercommandline的domain方法。hmastercommandline繼承自servercommandline類并且servercommandline類實作了tool接口。

domain方法内會調用toolrunner的run方法,檢視toolrunner類可以知道,實際上最後會調用hmastercommandline的run方法。

接下來會解析參數,根據參數值判斷是執行startmaster方法還是stopmaster方法。

startmaster方法中分兩種情況:本地模式和分布式模式。如果是分布式模式,通過反射調用hmaster的構造方法,并調用其start和join方法。

hmaster繼承自hasthread類,而hasthread類實作了runnable接口,故hmaster也是一個線程。

hmaster類繼承關系如下圖:

HBase源碼:HMaster啟動過程調試HMastermain方法HMaster類圖HMaster的構造方法run方法MasterFileSystem構造方法總結

1、構造方法總體過程

建立configuration并設定和擷取一些參數。包括:

在master上禁止block cache

設定服務端重試次數

擷取主機名稱和master綁定的ip和端口号,端口号預設為60000

設定regionserver的coprocessorhandler線程數為0

建立rpcserver(見下文分析)

初始化servername,其值為:<code>192.168.1.129,60000,1404117936154</code>

zk授權登入和hbase授權

設定目前線程名稱:<code>master + "-" + this.servername.tostring()</code>

判斷是否開啟複制:<code>replication.decoratemasterconfiguration(this.conf);</code>

設定<code>mapred.task.id</code>,如果其為空,則其值為:<code>"hb_m_" + this.servername.tostring()</code>

建立zookeeperwatcher監聽器(見下文分析),并在zookeeper上建立一些節點

啟動rpcserver中的線程

建立一個mastermetrics

判斷是否進行健康檢測:healthcheckchore

另外還初始化兩個參數:shouldsplitmetaseparately、waitingonlogsplitting

涉及到的參數有:

2、建立rpcserver并啟動其中的線程:

這部分涉及到rpc的使用,包括的知識點有<code>動态代理</code>、<code>java nio</code>等。

通過反射建立rpcengine的實作類,實作類可以在配置檔案中配置(<code>hbase.rpc.engine</code>),預設實作為writablerpcengine。 調用getserver方法,其實也就是new一個hbaseserver類。

構造方法中:

啟動一個listener線程,功能是監聽client的請求,将請求放入nio請求隊列,邏輯如下:

–&gt;建立n個selector,和一個n個線程的readpool,n由<code>ipc.server.read.threadpool.size</code>決定,預設為10

–&gt;讀取每個請求的頭和内容,将内容放入priorityqueue中

啟動一個responder線程,功能是将響應隊列裡的資料寫給各個client的connection通道,邏輯如下:

–&gt;建立nio selector

–&gt;預設逾時時間為15 mins

–&gt;依次将responsequeue中的内容寫回各通道,并關閉連接配接,buffer=8k

–&gt;如果該請求的傳回沒有寫完,則放回隊列頭,推遲再發送

–&gt;對于逾時未完成的響應,丢棄并關閉相應連接配接

啟動n(n預設為10)個handler線程,功能是處理請求隊列,并将結果寫到響應隊列

–&gt;讀取priorityqueue中的call,調用對應的call方法獲得value,寫回out并調用dorespond方法,處理該請求,并喚醒writable selector

–&gt;啟動m(m預設為0)個handler線程以處理priority

3、建立zookeeperwatcher

構造函數中生成如下持久節點:

接下來看hmaster的run方法做了哪些事情。

1、總體過程

建立monitoredtask,并把hmaster的狀态設定為master startup

啟動info server,即jetty伺服器,端口預設為60010,其對外提供兩個接口:/master-status和/dump

調用becomeactivemaster方法(見下文分析),阻塞等待直至目前master成為active master

當成為了master之後并且目前master程序正在運作,則調用finishinitialization方法(見下文分析),并且調用loop方法循環等待,一直到stop發生

當hmaster停止運作時候,會做以下事情:

清理startupstatus

停止balancerchore和catalogjanitorchore

讓regionservers shutdown

停止服務線程:rpcserver、logcleaner、hfilecleaner、infoserver、executorservice、healthcheckchore

停止以下線程:activemastermanager、catalogtracker、servermanager、assignmentmanager、filesystemmanager、snapshotmanager、zookeeper

2、becomeactivemaster方法:

建立activemastermanager

zookeeperwatcher注冊activemastermanager監聽器

調用stallifbackupmaster: –&gt;先檢查配置項 “hbase.master.backup”,自己是否backup機器,如果是則直接block直至檢查到系統中的active master挂掉(<code>zookeeper.session.timeout</code>,預設每3分鐘檢查一次)

建立clusterstatustracker并啟動

調用activemastermanager的blockuntilbecomingactivemaster方法。

建立短暫的”/hbase/master”,此節點值為version+servername,如果建立成功,則删除備份節點;否則,建立備份節點

獲得”/hbase/master”節點上的資料,如果不為null,則獲得servername,并判斷是否是在目前節點上建立了”/hbase/master”,如果是則删除該節點,這是因為該節點已經是備份節點了。

3、finishinitialization方法:

建立masterfilesystem對象,封裝了master常用的一些檔案系統操作,包括splitlog file、删除region目錄、删除table目錄、删除cf目錄、檢查檔案系統狀态等.

建立fstabledescriptors對象

設定叢集id

如果不是備份master:

建立executorservice,維護一個executormap,一種event對應一個executor(線程池).可以送出eventhandler來執行異步事件; - 建立servermanager,管理regionserver資訊,維護着onlineregion server 和deadregion server清單,處理regionserver的startups、shutdowns、 deaths,同時也維護着每個regionserver rpc stub.

調用initializezkbasedsystemtrackers,初始化zk檔案系統

建立catalogtracker, 它包含rootregiontracker和metanodetracker,對應”/hbase/root-region-server”和/”hbase/unassigned/1028785192”這兩個結點(1028785192是.meta.的分區名)。如果之前從未啟動過hbase,那麼在start catalogtracker時這兩個結點不存在。”/hbase/root-region-server”是一個持久結點,在rootlocationeditor中建立

建立 loadbalancer,負責region在regionserver之間的移動,關于balancer的政策,可以通過hbase.regions.slop來設定load區間

建立 assignmentmanager,負責管理和配置設定region,同時它也會接受zk上關于region的event,根據event來完成region的上下線、關閉打開等工作。

建立 regionservertracker: 監控”/hbase/rs”結點,通過zk的event來跟蹤onlineregion servers, 如果有rs下線,删除servermanager中對應的onlineregions.

建立 drainingservertracker: 監控”/hbase/draining”結點

建立 clusterstatustracker,監控”/hbase/shutdown”結點維護叢集狀态

建立snapshotmanager

如果不是備份master,初始化mastercoprocessorhost并執行startservicethreads()。說明:<code>info server的啟動移到構造函數了去了,這樣可以早點通過jetty伺服器檢視hmaster啟動狀态。</code>

建立一些executorservice

建立logcleaner并啟動

建立hfilecleaner并啟動

啟動healthcheckchore

打開rpcserver

等待regionserver注冊。滿足以下這些條件後傳回目前所有region server上的region數後繼續:

a 至少等待4.5s,”hbase.master.wait.on.regionservers.timeout”

b 成功啟動regionserver節點數&gt;=1,”hbase.master.wait.on.regionservers.mintostart”

c 1.5s内沒有regionsever死掉或重新啟動,<code>hbase.master.wait.on.regionservers.interval</code>)

servermanager注冊新的線上region server

如果不是備份master,啟動assignmentmanager

擷取下線的region server,然後拆分hlog

–&gt;依次檢查每一個hlog目錄,檢視它所屬的region server是否online,如果是則不需要做任何動作,region server自己會恢複資料,如果不是,則需要将它配置設定給其它的region server

–&gt;split是加鎖操作:

–&gt; 建立一個新的hlogsplitter,周遊每一個server目錄下的所有hlog檔案,依次做如下操作。(如果遇到檔案損壞等無法跳過的錯誤,配 置<code>hbase.hlog.split.skip.errors=true</code> 以忽略之)

–&gt;啟動<code>hbase.regionserver.hlog.splitlog.writer.threads</code>(預設為3)個線程,共使用128mb記憶體,啟動這些寫線程

–&gt;先通過lease機制檢查檔案是否能夠append,如果不能則死循環等待

–&gt;把hlog中的内容全部加載到記憶體中(記憶體同時被幾個寫線程消費))

–&gt;把有損壞并且跳過的檔案移到<code>/hbase/.corrupt/</code>目錄中

–&gt; 把其餘己經處理過的檔案移到<code>/hbase/.oldlogs</code>中,然後删除原有的server目錄

–&gt; 等待寫線程結束,傳回新寫的所有路徑

–&gt;解鎖

寫線程邏輯:

–&gt;從記憶體中讀出每一行資料的key和value,然後查詢相應的region路徑。如果該region路徑不存在,說明該region很可能己經被split了,則不處理這部分資料,因為此時忽略它們是安全的。

–&gt;如果上一步能查到相應的路徑,則到對應路徑下建立”recovered.edits”檔案夾(如果該檔案夾存在則删除後覆寫之),然後将資料寫入該檔案夾

調用assignroot方法,檢查是否配置設定了-root-表,如果沒有,則通過assignmentmanager.assignroot()來配置設定root表,并激活該表

運作this.servermanager.enablesshforroot()方法

拆分.meta. server上的hlog

配置設定.meta.表

enableservershutdownhandler

處理dead的server

assignmentmanager.joincluster();

設定balancer

fixupdaughters(status)

如果不是備份master

啟動balancerchore線程,運作loadbalancer

啟動startcatalogjanitorchore,周期性掃描<code>.meta.</code>表上未使用的region并回收

registermbean

servermanager.cleardeadserverswithsamehostnameandportofonlineserver,清理dead的server

如果不是備份master,cphost.poststartmaster

在<code>hmaster.finishinitialization</code>方法中觸發了masterfilesystem的構造方法,該類在hmaster類中會被以下類使用:

logcleaner

hfilecleaner

另外該類可以完成拆分log的工作:

這裡主要是關心建立了哪些目錄,其他用途暫不分析。

1、接下來,看其構造方法運作過程:

擷取rootdir:由參數<code>hbase.rootdir</code>配置

擷取tempdir:<code>${hbase.rootdir}/.tmp</code>

擷取檔案系統的uri,并設定到<code>fs.default.name</code>和<code>fs.defaultfs</code>

判斷是否進行分布式檔案拆分,參數:<code>hbase.master.distributed.log.splitting</code>,如果需要,則建立splitlogmanager

建立oldlogdir,調用createinitialfilesystemlayout方法

checkrootdir

等待fs退出安全模式(預設10秒鐘輪循一次,可通過參數<code>hbase.server.thread.wakefrequency</code>調整

如果hbase.rootdir目錄不存在則建立它,然後在此目錄中建立名為”hbase.version”的檔案,内容是檔案系統版本号,目前為7;如果hbase.rootdir目錄已存在,則讀出”hbase.version”檔案的内容與目前的版本号相比,如果不相等,則列印錯誤資訊(提示版本不對),抛出異常filesystemversionexception

檢查<code>${hbase.rootdir}</code>目錄下是否有名為”hbase.id”的檔案,如果沒有則建立它,内容是随機生成的uuid(總長度36位,由5部份組成,用”-“分隔),如:6c43f934-37a2-4cae-9d49-3f5abfdc113d

讀出”hbase.id”的檔案的内容存到clusterid字段

判斷hbase.rootdir目錄中是否有”-root-/70236052”目錄,沒有的話說明是第一次啟動hbase,進入bootstrap方法

createroottableinfo 建立”-root-“表的描述檔案,判斷<code>hbase.rootdir/-root-</code>目錄中是否存在tableinfo開頭的檔案,另外還建立了.tmp目錄

checktempdir

如果oldlogdir(<code>${hbase.rootdir}/.oldlogs</code>)不存在,則建立

2、bootstrap方法運作過程:

調用hregion.createhregion建立”-root-“分區和”.meta.”分區

把”.meta.”分區資訊加到”-root-“表,并關閉分區和hlog

經過上面分析之後,來看看zookeeper建立的一些目錄分布式由哪個類來監控的:

<code>/hbase</code>

<code>/hbase/root-region-server</code>:rootregiontracker,監控root所在的regionserver

<code>/hbase/rs</code>:regionservertracker,監控regionserver的上線和下線

<code>/table/draining</code>:drainingservertracker,監聽regionserver清單的變化

<code>/hbase/master</code>:在hmaster中建立,并且是一個短暫結點,結點的值是hmaster的servername:<code>hostname,port,目前毫秒</code>

<code>/hbase/backup-masters</code>

<code>/hbase/shutdown</code>:clusterstatustracker,當hmaster啟動之後,會将目前時間(<code>bytes.tobytes(new java.util.date().tostring())</code>)存到該節點

<code>/hbase/unassigned</code>:metanodetracker

<code>/hbase/table94</code>

<code>/hbase/table</code>

<code>/hbase/hbaseid</code>:在<code>hmaster.finishinitialization</code>方法中調用clusterid.setclusterid建立,結點值是uuid

<code>/hbase/splitlog</code>

在hmaster啟動之後,<code>${hbase.rootdir}</code>目錄如下:

簡單總結一下hmaster啟動過程做了哪些事情:

建立rpcserver,及hbaseserver

建立zookeeperwatcher監聽器

阻塞等待成為activemaster

建立master的一些檔案目錄

初始化一些基于zk的跟蹤器

建立loadbalancer

建立jetty的infoserver并啟動

啟動健康檢查

等待regionserver注冊

從hlog中恢複資料

配置設定root和meta表

配置設定region

運作負載均衡線程

周期性掃描.meta.表上未使用的region并回收