Hbase是kv存儲,但是邏輯上我們可以把存儲在hbase上的kv數據當成表,rowkey可以認為是表的主鍵。為了便於分布式操作,hbase會把表橫向切分成一塊一塊的數據,而每塊就是一個Region。為了提供在線服務,我們必須把Region加載到集群中的某台機器上,這個加載的過程正是region assign要做的。順便說一句,hbase中把表切分region和HDFS中文件切分成block,Spark中RDD切分成partitions的思想都是一樣的。
region assgin的流程
region assgin涉及到client,master,regionserver以及zk之間的交互。主要步驟如下:
1,client向master發送AssignRegion的RPC請求后(如當在hbase shell中運行assign命令),master響應該服務的入口函數為:
1 public AssignRegionResponse assignRegion(RpcController controller, 2 AssignRegionRequest req) throws ServiceException { 3 ... 4 //檢查master端服務是否啟動以及已經初始化 5 master.checkInitialized(); 6 //協處理器preAssign 7 ... 8 9 //核心,使用AssignmentManager做region assignment 10 master.assignmentManager.assign(regionInfo, true, true); 11 //協處理器postAssign 12 ... 13 }
入口函數調用的assgin函數主要實現如下:
1 public void assign(HRegionInfo region, 2 boolean setOfflineInZK, boolean forceNewPlan) { 3 //檢查該table是否處於disable或者disabling狀態 4 //如果是,則忽略此次assign操作,並且如果該region處於RS_ZK_REGION_CLOSED, 5 //M_ZK_REGION_OFFLINE狀態,則刪除RIT下該節點 6 //另外,還會將master中該region相關的數據結構(RegionStates)的狀態做相應設置 7 if (isDisabledorDisablingRegionInRIT(region)) { 8 return; 9 } 10 String encodedName = region.getEncodedName(); 11 //貌似主要是鎖住該region對應的狀態 12 Lock lock = locker.acquireLock(encodedName); 13 try { 14 //根據該region當前的狀態,進行相關預操作和過濾, 15 //比如,如果region處於FAILED_CLOSE和FAILD_OPEN狀態會先進行unassign操作 16 //最終使得region處於offline狀態 17 forceRegionStateToOffline(region, forceNewPlan); 18 19 //嘗試maximumAttempts(默認10次),首先獲取RegionPlan, 20 //然后設置zk下RIT對應region的狀態為M_ZK_REGION_OFFLINE 21 //一切准備就緒后,master會設置regionStates為PENDING_OPEN狀態,並且 22 //向RegionServer發送OpenRegion請求 23 assign(state, ...); 24 } 25 } finally { 26 lock.unlock(); 27 } 28 }
2,ReionServer響應OpenRegion的請求函數如下:
public OpenRegionResponse openRegion(final RpcController controller, final OpenRegionRequest request) throws ServiceException { ... //正常情況下,會交由OpenRegionHanlder來處理 regionServer.service.submit(new OpenRegionHandler( regionServer, regionServer, region, htd, masterSystemTime, coordination, ord)); ... //打開后設置狀態返回 builder.addOpeningState(RegionOpeningState.OPENED); }
而OpenRegionHandler中open region的核心代碼process函數中:
1 public void process() throws IOException { 2 ... 3 //transitionFromOfflineToOpening會將zk中該region的狀態從M_ZK_REGION_OFFLINE狀態設置成RS_ZK_REGION_OPENING狀態 4 if (useZKForAssignment 5 && !coordination.transitionFromOfflineToOpening(reg...) 6 7 //打開open region,細節暫時忽略 8 openRegion() 9 10 //transitionToOpened將zk中該region的狀態從RS_ZK_REGION_OPENING設置成 11 //RS_ZK_REGION_OPENED 12 if (!isRegionStillOpening() || 13 (useZKForAssignment && !coordination.transitionToOpened(region, ord))) { 14 }
3,接下來,再看看Master監控到zk中region狀態變化的相應情況:
1 void handleRegion(final RegionTransition rt, OpenRegionCoordination coordination, 2 OpenRegionCoordination.OpenRegionDetails ord) { 3 //當zk的狀態變成RS_ZK_REGION_OPENING,設置regionStates的狀態為OPENING 4 case RS_ZK_REGION_OPENING: 5 regionStates.updateRegionState(rt, State.OPENING); 6 7 //正如注釋所言,剔除中間狀態,刪除zk RIT結點,RegionStates設置為OPEN 8 case RS_ZK_REGION_OPENED: 9 // Handle OPENED by removing from transition and deleted zk node 10 regionStates.transitionOpenFromPendingOpenOrOpeningOnServer(...); 11 12 }
小結
通過上面的分析,Region Assgin過程中主要的狀態和步驟,大概可以用下圖來概括。

未來
從上面的分析可知,當前region assgin的流程還是非常復雜的,所有很容易就造成Meta表和master,zk中的狀態不一致,從而使Region處於RIT狀態。社區正在做這方面的優化,主要思想就是去掉zk依賴,從而只依賴master和regionserver。具體詳情可參看: https://blogs.apache.org/hbase/entry/hbase_zk_less_region_assignment 。 預計在hbase 2.0中將包含該功能。
