—client 的調用流程
delete 數據的流程.(table.delete(deleteColumn);)
(源碼基於hbase-1.1.5版本)
HTable table = new HTable(conf, Bytes.toBytes(tableName));
HTable 對象創建時調用如下方法創建對遠程的鏈接對象管理器
ConnectionManager.getConnectionInternal(conf)
ConnectionFactory.createConnection(conf, managed, pool, user)
默認爲 HConnectionImplementation 類
通過 ZooKeeperRegistry.getClusterId 拿到集羣的id
在該方法中調用
HConnectionImplementation.getKeepAliveZooKeeperWatcher
拿到zk的鏈接
然後調用如下方法拿到clousterId
this.clusterId = ZKClusterId.readClusterIdZNode(zkw);
接下來創建rpcclient
this.rpcClient = RpcClientFactory.createClient(this.conf, this.clusterId);
實現類爲 RpcClientImpl
這樣一個hbase對象的創建就完成了。
table.delete(deleteColumn);開始調用。
創建一個 RegionServerCallable 對象
RegionServerCallable<Boolean> callable = new RegionServerCallable<Boolean>(connection,tableName, delete.getRow())
包含了要刪除的對應的表名和那一行。
然後通過調用一下多次嘗試的對象調用
rpcCallerFactory.<Boolean> newCaller(rpcTimeout).callWithRetries(callable, this.operationTimeout);
在caller中,會調用到callable.prepare,進行初始化。
在初始化的時候,要拿到對應的regionserver信息
try (RegionLocator regionLocator = connection.getRegionLocator(tableName)) {
this.location = regionLocator.getRegionLocation(row, reload);
}
然後通過讀取的是那一個主鍵,去進行定
locateRegion(tableName, row, useCache, retry, RegionReplicaUtil.DEFAULT_REPLICA_ID)
然後拼接要刪除的行的對象
byte[] metaKey = HRegionInfo.createRegionName(tableName, row, HConstants.NINES, false);
通過創建
Scan s = new Scan();
s.setReversed(true);
s.setStartRow(metaKey);
s.setSmall(true);
s.setCaching(1);
對象到發送到 meta元數據中進行查詢
rcs = new ClientSmallReversedScanner(conf, s, TableName.META_TABLE_NAME, this,
rpcCallerFactory, rpcControllerFactory, getMetaLookupPool(), 0);
然後發起對 hbase:meta 元數據表的查詢
smallScanCallable = callableFactory.getCallable(getConnection(), getTable(), scan,
getScanMetrics(), localStartKey, cacheNum, rpcControllerFactory, getPool(),
getPrimaryOperationTimeout(), getRetries(), getScannerTimeout(), getConf(), caller);
然後發起了查詢了
values = this.caller.callWithoutRetries(smallScanCallable, scannerTimeout);
然後創建對hbase:meta表的查詢請求
RegionLocations rl = RpcRetryingCallerWithReadReplicas.getRegionLocations(true,
RegionReplicaUtil.DEFAULT_REPLICA_ID, cConnection, tableName,
currentScannerCallable.getRow());
在getRegionLocations 方法中
rl = cConnection.locateRegion(tableName, row, useCache, true, replicaId);
發起元數據遠程連接的調用
@Override
public RegionLocations locateRegion(final TableName tableName,
final byte [] row, boolean useCache, boolean retry, int replicaId)
throws IOException {
if (this.closed) throw new IOException(toString() + " closed");
if (tableName== null || tableName.getName().length == 0) {
throw new IllegalArgumentException(
"table name cannot be null or zero length");
}
if (tableName.equals(TableName.META_TABLE_NAME)) {
return locateMeta(tableName, useCache, replicaId);
} else {
// Region not in the cache - have to go to the meta RS
return locateRegionInMeta(tableName, row, useCache, retry, replicaId);
}
}
通過判斷是否是元數據表,進行不同的定位,如果是元數據,就去zk中進行讀取,否則,
在元數據中
locations = this.registry.getMetaRegionLocation();
拿到meta元數據的位置信息,這個meta元數據的位置信息是存放在zk中的
通過下面的方法讀取
List<ServerName> servers = new MetaTableLocator().blockUntilAvailable(zkw, hci.rpcTimeout,
hci.getConfiguration());
拿到後,會緩存在client端
然後就創建到hmaster的連接了
setStub(super.getConnection().getClient(dest));(dest=myubuntu,16020,1468468352472)
創建直接到這個目標端口的rpc 客戶端連接
BlockingRpcChannel channel =
this.rpcClient.createBlockingRpcChannel(sn, user, rpcTimeout);
stub = ClientService.newBlockingStub(channel);
創建了 BlockingRpcChannelImplementation對象
真正發起了請求了(這個時候的tableName ==hbase:meta)還是元數據表
@Override
public Result[] call(int timeout) throws IOException {
if (this.closed) return null;
if (Thread.interrupted()) {
throw new InterruptedIOException();
}
ScanRequest request = RequestConverter.buildScanRequest(getLocation()
.getRegionInfo().getRegionName(), getScan(), getCaching(), true);
ScanResponse response = null;
controller = controllerFactory.newController();
try {
controller.setPriority(getTableName());
controller.setCallTimeout(timeout);
response = getStub().scan(controller, request);
Result[] results = ResponseConverter.getResults(controller.cellScanner(),
response);
if (response.hasMoreResultsInRegion()) {
setHasMoreResultsContext(true);
setServerHasMoreResults(response.getMoreResultsInRegion());
} else {
setHasMoreResultsContext(false);
}
// We need to update result metrics since we are overriding call()
updateResultsMetrics(results);
return results;
} catch (ServiceException se) {
throw ProtobufUtil.getRemoteException(se);
}
}
request 對象內容爲(blog2爲我要刪除的表。rowkey1爲我要刪除的主鍵)
region {
type: REGION_NAME
value: "hbase:meta,,1"
}
scan {
start_row: "blog2,rowkey1,99999999999999"
max_versions: 1
cache_blocks: true
small: true
reversed: true
caching: 1
}
number_of_rows: 1
close_scanner: true
client_handles_partials: true
client_handles_heartbeats: true
然後在 RpcClientImpl 的Connection對象的創建過程中
設置了servicename =ClientService
ConnectionHeader.Builder builder = ConnectionHeader.newBuilder();
builder.setServiceName(remoteId.getServiceName());
UserInformation userInfoPB = getUserInfo(ticket);
if (userInfoPB != null) {
builder.setUserInfo(userInfoPB);
}
if (this.codec != null) {
builder.setCellBlockCodecClass(this.codec.getClass().getCanonicalName());
}
if (this.compressor != null) {
builder.setCellBlockCompressorClass(this.compressor.getClass().getCanonicalName());
}
builder.setVersionInfo(ProtobufUtil.getVersionInfo());
this.header = builder.build();
這樣就設置了頭部信息了
然後就根據剛纔創建的connection信息,進行了發送查詢
final Call call = new Call(this.callIdCnt.getAndIncrement(), md, param, cells, returnType,
pcrc.getCallTimeout());
final Connection connection = getConnection(ticket, call, addr);
connection.tracedWriteRequest(call, pcrc.getPriority(), Trace.currentSpan());
然後現在就連接到遠程 setupIOstreams();
NetUtils.connect(this.socket, remoteId.getAddress(), connectTO);
在這裏直接發送數據過去了
IPCUtil.write(this.out, header, call.param, cellBlock);
當把結果拿到後
setStub(getConnection().getClient(this.location.getServerName()));
(location = region=blog2,,1468401068588.f8572806e5866a27ccf7464ec899bb18., hostname=myubuntu,16020,1468468352472, seqNum=25)
就可以連接到具體的那個業務表的regionserver了
拿到地址後,最後回調回對原始方法的調用
public void delete(final Delete delete)
throws IOException {
RegionServerCallable<Boolean> callable = new RegionServerCallable<Boolean>(connection,
tableName, delete.getRow()) {
@Override
public Boolean call(int callTimeout) throws IOException {
PayloadCarryingRpcController controller = rpcControllerFactory.newController();
controller.setPriority(tableName);
controller.setCallTimeout(callTimeout);
try {
MutateRequest request = RequestConverter.buildMutateRequest(
getLocation().getRegionInfo().getRegionName(), delete);
MutateResponse response = getStub().mutate(controller, request);
return Boolean.valueOf(response.getProcessed());
} catch (ServiceException se) {
throw ProtobufUtil.getRemoteException(se);
}
}
};
rpcCallerFactory.<Boolean> newCaller(rpcTimeout).callWithRetries(callable,
this.operationTimeout);
}
tableName = blog2
最終返回到用戶了