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中将包含该功能。