hbase客戶端源碼分析調用

—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

最終返回到用戶了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章