Ch14-HBase 之 CreateTable
April 9, 2021
HBase CreateTable
1. CreateTable 涉及到的模块说明 #
创建表的整个流程主要分为两大块,一大块是 Client 端,主要用于构造 RPC 请求,另一大块是 Master 端,主要负责实际的建表流程。
整个流程借助上图还是比较容易理解的。因为 Procedure v2 框架的引入,客户端根据需要仅仅发送请求便可,然后实际的建表就交给 Procedure v2 进行实际的操作。
1.1 创建表的 RPC 消息结构 #
message TableSchema {
optional TableName table_name = 1;
repeated BytesBytesPair attributes = 2;
repeated ColumnFamilySchema column_families = 3;
repeated NameStringPair configuration = 4;
}
message CreateTableRequest {
required TableSchema table_schema = 1;
repeated bytes split_keys = 2;
optional uint64 nonce_group = 3 [default = 0];
optional uint64 nonce = 4 [default = 0];
}
message CreateTableResponse {
optional uint64 proc_id = 1;
}
service MasterService {
/** Creates a new table asynchronously */
rpc CreateTable(CreateTableRequest) returns(CreateTableResponse);
/** Deletes a table */
rpc DeleteTable(DeleteTableRequest) returns(DeleteTableResponse);
}
2. 创建表的流程介绍 #
public boolean create(TableDescriptor table) {
try (Admin admin = connection.getAdmin()) {
admin.createTable(table);
} catch (IOException e) {
return false;
}
return true;
}
整个建表的代码段大概如上所示,看起来比较简单,但是实际整个流程异常的繁琐。
2.1 HBase Client 的流程 #
当调用 admin.createTable(table) 语句创建表时,会通过层层调用,最后由 MasterService 调用 BlockingInterface 发送 rpc 请求,请求的报文体则如前面 Protobuf 给出的结构。 HMaster 接收到该请求后会执行后续逻辑,同时会返回一个 proc Id,该 id 最终会被封装成 HBaseAdmin.CreateTableFuture 类,定时查询 proc Id 对应的 Procedure 执行结果,直到最后建表成功。
简易版的如上图所示,完整版的如下图所示:
2.2 HBase Master 的流程 #
HBase Master 的流程较为繁琐,主要负责执行 Procedure。具体 Procedure 的工作原理,本节不再赘述,可以参考《HBase Procedure v2 原理说明》一节。这里直接开始讲述 Procedure 如何执行。
Procedure 从 MasterProcedureScheduler 维护的 tableRunQueue 队列中取出 CreateTableProcedure 开始调用执行其中的 executeFromState() 方法。这部分代码即整个建表的核心逻辑。
@Override
protected Flow executeFromState(final MasterProcedureEnv env, final CreateTableState state) throws InterruptedException {
LOG.info("{} execute state={}", this, state);
try {
switch (state) {
case CREATE_TABLE_PRE_OPERATION:
...
preCreate(env);
setNextState(CreateTableState.CREATE_TABLE_WRITE_FS_LAYOUT);
break;
case CREATE_TABLE_WRITE_FS_LAYOUT:
...
env.getMasterServices().getTableDescriptors().update(tableDescriptor, true);
setNextState(CreateTableState.CREATE_TABLE_ADD_TO_META);
break;
case CREATE_TABLE_ADD_TO_META:
newRegions = addTableToMeta(env, tableDescriptor, newRegions);
setNextState(CreateTableState.CREATE_TABLE_ASSIGN_REGIONS);
break;
case CREATE_TABLE_ASSIGN_REGIONS:
setEnablingState(env, getTableName());
addChildProcedure(env.getAssignmentManager().createRoundRobinAssignProcedures(newRegions));
setNextState(CreateTableState.CREATE_TABLE_UPDATE_DESC_CACHE);
break;
case CREATE_TABLE_UPDATE_DESC_CACHE:
setEnabledState(env, getTableName());
setNextState(CreateTableState.CREATE_TABLE_POST_OPERATION);
break;
case CREATE_TABLE_POST_OPERATION:
postCreate(env);
return Flow.NO_MORE_STATE;
default:
throw new UnsupportedOperationException("unhandled state=" + state);
}
} catch (IOException e) {
if (isRollbackSupported(state)) {
setFailure("master-create-table", e);
} else {
LOG.warn("Retriable error trying to create table=" + getTableName() + " state=" + state, e);
}
}
return Flow.HAS_MORE_STATE;
}
上述代码转换成流程图如下所示,可以看到因为 Procedure v2 的存在,整个建表流程被拆的非常琐碎,如果途中出现了异常,那么会在 Failure 中将本次 Procedure 的状态设置为 FAILED,后续尝试回滚截至该步骤的所有操作所产生的行为。
2.2 HBase RegionServer 的流程 #
HBase Master 建表流程走到CREATE_TABLE_ASSIGN_REGIONS
这一步的时候,会创建出一个 SubProcedure,该 SubProcedure 会调用CREATE_TABLE_ASSIGN_REGIONS将 Region 分配到各个 RegionServer 上面。