HBase Client Get 源码分析
来源:互联网 发布:三工序雕刻机编程软件 编辑:程序博客网 时间:2024/05/18 16:18
1 入口
HTable.java
private Result get(Get get, final boolean checkExistenceOnly) throws IOException { // if we are changing settings to the get, clone it. if (get.isCheckExistenceOnly() != checkExistenceOnly || get.getConsistency() == null) { get = ReflectionUtils.newInstance(get.getClass(), get); get.setCheckExistenceOnly(checkExistenceOnly); if (get.getConsistency() == null){ get.setConsistency(defaultConsistency); } } if (get.getConsistency() == Consistency.STRONG) { // Good old call. final Get getReq = get; RegionServerCallable<Result> callable = new RegionServerCallable<Result>(this.connection, getName(), get.getRow()) { @Override public Result call(int callTimeout) throws IOException { ClientProtos.GetRequest request = RequestConverter.buildGetRequest(getLocation().getRegionInfo().getRegionName(), getReq); PayloadCarryingRpcController controller = rpcControllerFactory.newController(); controller.setPriority(tableName); controller.setCallTimeout(callTimeout); try { ClientProtos.GetResponse response = getStub().get(controller, request); if (response == null) return null; return ProtobufUtil.toResult(response.getResult()); } catch (ServiceException se) { throw ProtobufUtil.getRemoteException(se); } } }; return rpcCallerFactory.<Result>newCaller().callWithRetries(callable, this.operationTimeout); }
这里注意两个地方:
1.1 callable的类型是RegionServerCallable<Result>, 同时覆盖了call函数,这里后面需要回来看。
1.2 最后一行callWithRetries
2 继续跟踪代码
public T callWithRetries(RetryingCallable<T> callable, int callTimeout) throws IOException, RuntimeException { List<RetriesExhaustedException.ThrowableWithExtraContext> exceptions = new ArrayList<RetriesExhaustedException.ThrowableWithExtraContext>(); this.globalStartTime = EnvironmentEdgeManager.currentTime(); context.clear(); for (int tries = 0;; tries++) { long expectedSleep; try { callable.prepare(tries != 0); // if called with false, check table status on ZK interceptor.intercept(context.prepare(callable, tries)); return callable.call(getRemainingTime(callTimeout)); } catch (PreemptiveFastFailException e) { throw e; } catch (Throwable t) { ExceptionUtil.rethrowIfInterrupt(t); if (tries > startLogErrorsCnt) { LOG.info("Call exception, tries=" + tries + ", retries=" + retries + ", started=" + (EnvironmentEdgeManager.currentTime() - this.globalStartTime) + " ms ago, " + "cancelled=" + cancelled.get() + ", msg=" + callable.getExceptionMessageAdditionalDetail()); } // translateException throws exception when should not retry: i.e. when request is bad. interceptor.handleFailure(context, t); t = translateException(t); callable.throwable(t, retries != 1); RetriesExhaustedException.ThrowableWithExtraContext qt = new RetriesExhaustedException.ThrowableWithExtraContext(t, EnvironmentEdgeManager.currentTime(), toString()); exceptions.add(qt); if (tries >= retries - 1) { throw new RetriesExhaustedException(tries, exceptions); } // If the server is dead, we need to wait a little before retrying, to give // a chance to the regions to be // tries hasn't been bumped up yet so we use "tries + 1" to get right pause time expectedSleep = callable.sleep(pause, tries + 1); // If, after the planned sleep, there won't be enough time left, we stop now. long duration = singleCallDuration(expectedSleep); if (duration > callTimeout) { String msg = "callTimeout=" + callTimeout + ", callDuration=" + duration + ": " + callable.getExceptionMessageAdditionalDetail(); throw (SocketTimeoutException)(new SocketTimeoutException(msg).initCause(t)); } } finally { interceptor.updateFailureInfo(context); } try { if (expectedSleep > 0) { synchronized (cancelled) { if (cancelled.get()) return null; cancelled.wait(expectedSleep); } } if (cancelled.get()) return null; } catch (InterruptedException e) { throw new InterruptedIOException("Interrupted after " + tries + " tries on " + retries); } } }
重点观察两个地方:
2.1 callable.prepare, 这里要注意callable的类型,见上面一步,
2.2 callable.call
2.1 RegionServerCallable.java
public void prepare(final boolean reload) throws IOException { try (RegionLocator regionLocator = connection.getRegionLocator(tableName)) { this.location = regionLocator.getRegionLocation(row, reload); } if (this.location == null) { throw new IOException("Failed to find location, tableName=" + tableName + ", row=" + Bytes.toString(row) + ", reload=" + reload); } setStub(getConnection().getClient(this.location.getServerName())); }
2.1.1 setStub函数会找到合适的RPC client, 注意返回的client的类型
HConnection.java
ClientService.BlockingInterface getClient(final ServerName serverName) throws IOException;
2.2 call函数是被覆盖的,所以观察 1 中的call函数
ClientProtos.GetResponse response = getStub().get(controller, request);
继续跟踪
ClientProtos.java
public interface BlockingInterface { public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetResponse get( com.google.protobuf.RpcController controller, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetRequest request) throws com.google.protobuf.ServiceException;
这里的接口方法的实现类
ClientProtos.java --》 BlockingStub
private static final class BlockingStub implements BlockingInterface { private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) { this.channel = channel; } private final com.google.protobuf.BlockingRpcChannel channel; public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetResponse get( com.google.protobuf.RpcController controller, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetRequest request) throws com.google.protobuf.ServiceException { return (org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetResponse) channel.callBlockingMethod( getDescriptor().getMethods().get(0), controller, request, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetResponse.getDefaultInstance()); }
这里的重点是channel.callBlockingMethod
public interface BlockingRpcChannel { Message callBlockingMethod(MethodDescriptor var1, RpcController var2, Message var3, Message var4) throws ServiceException;}
实现类
AbstractRpcClient.java
public static class BlockingRpcChannelImplementation implements BlockingRpcChannel { private final InetSocketAddress isa; private final AbstractRpcClient rpcClient; private final User ticket; private final int channelOperationTimeout; /** * @param channelOperationTimeout - the default timeout when no timeout is given */ protected BlockingRpcChannelImplementation(final AbstractRpcClient rpcClient, final ServerName sn, final User ticket, int channelOperationTimeout) { this.isa = new InetSocketAddress(sn.getHostname(), sn.getPort()); this.rpcClient = rpcClient; this.ticket = ticket; this.channelOperationTimeout = channelOperationTimeout; } @Override public Message callBlockingMethod(Descriptors.MethodDescriptor md, RpcController controller, Message param, Message returnType) throws ServiceException { PayloadCarryingRpcController pcrc; if (controller != null) { pcrc = (PayloadCarryingRpcController) controller; if (!pcrc.hasCallTimeout()) { pcrc.setCallTimeout(channelOperationTimeout); } } else { pcrc = new PayloadCarryingRpcController(); pcrc.setCallTimeout(channelOperationTimeout); } return this.rpcClient.callBlockingMethod(md, pcrc, param, returnType, this.ticket, this.isa); } }
rpcClient.callBlockingMethod的实现
Message callBlockingMethod(Descriptors.MethodDescriptor md, PayloadCarryingRpcController pcrc, Message param, Message returnType, final User ticket, final InetSocketAddress isa) throws ServiceException { if (pcrc == null) { pcrc = new PayloadCarryingRpcController(); } long startTime = 0; if (LOG.isTraceEnabled()) { startTime = EnvironmentEdgeManager.currentTime(); } Pair<Message, CellScanner> val; try { val = call(pcrc, md, param, returnType, ticket, isa); // Shove the results into controller so can be carried across the proxy/pb service void. pcrc.setCellScanner(val.getSecond()); if (LOG.isTraceEnabled()) { long callTime = EnvironmentEdgeManager.currentTime() - startTime; LOG.trace("Call: " + md.getName() + ", callTime: " + callTime + "ms"); } return val.getFirst(); } catch (Throwable e) { throw new ServiceException(e); } }
call函数
protected abstract Pair<Message, CellScanner> call(PayloadCarryingRpcController pcrc, Descriptors.MethodDescriptor md, Message param, Message returnType, User ticket, InetSocketAddress isa) throws IOException, InterruptedException;
这里的call函数有两个实现
AsyncRpcClient.java
RpcClientImpl.java
目前Get请求使用的是RpcClientImpl
protected Pair<Message, CellScanner> call(PayloadCarryingRpcController pcrc, MethodDescriptor md, Message param, Message returnType, User ticket, InetSocketAddress addr) throws IOException, InterruptedException { if (pcrc == null) { pcrc = new PayloadCarryingRpcController(); } CellScanner cells = pcrc.cellScanner(); final Call call = new Call(this.callIdCnt.getAndIncrement(), md, param, cells, returnType, pcrc.getCallTimeout()); final Connection connection = getConnection(ticket, call, addr); final CallFuture cts; if (connection.callSender != null) { cts = connection.callSender.sendCall(call, pcrc.getPriority(), Trace.currentSpan()); pcrc.notifyOnCancel(new RpcCallback<Object>() { @Override public void run(Object parameter) { connection.callSender.remove(cts); } }); if (pcrc.isCanceled()) { // To finish if the call was cancelled before we set the notification (race condition) call.callComplete(); return new Pair<Message, CellScanner>(call.response, call.cells); } } else { cts = null; connection.tracedWriteRequest(call, pcrc.getPriority(), Trace.currentSpan()); } while (!call.done) { if (call.checkAndSetTimeout()) { if (cts != null) connection.callSender.remove(cts); break; } if (connection.shouldCloseConnection.get()) { throw new ConnectionClosingException("Call id=" + call.id + " on server " + addr + " aborted: connection is closing"); } try { synchronized (call) { if (call.done) break; call.wait(Math.min(call.remainingTime(), 1000) + 1); } } catch (InterruptedException e) { call.setException(new InterruptedIOException()); if (cts != null) connection.callSender.remove(cts); throw e; } } if (call.error != null) { if (call.error instanceof RemoteException) { call.error.fillInStackTrace(); throw call.error; } // local exception throw wrapException(addr, call.error); } return new Pair<Message, CellScanner>(call.response, call.cells); }
如果Get请求超时20分钟,call.checkAndSetTimeout函数会抛出exception
java.net.SocketTimeoutException: callTimeout=1200000, callDuration=1209076: row '/dict/BPE_CUSTOMER_CONTACT.CUSTOMER_CONTACT_DATA_SUMMARY_V2/CONTACT_AREA/b0372936-96c6-45e4-9927-bce9060d55db.dict' on table 'tableX' at region=tableX,/cube_statistics/v_clsfd_ga_trffc_src_7D_v1/1fb0f3d2-a3ce-4027-990c-3549b2594006.seq,1451389955012.9a10b3032bb086d76f6037d17c16c3e2., hostname=phx9dn0486.phx.xx.com,60020,1476310334343, seqNum=35251· Caused by: java.io.IOException: Call tophx9dn0486.phx.xx.com/10.115.11.16:60020 failed on local exception: org.apache.hadoop.hbase.ipc.CallTimeoutException: Call id=418960885, waitTime=1200001, operationTimeout=1200000 expired.
· at org.apache.hadoop.hbase.ipc.RpcClientImpl.wrapException(RpcClientImpl.java:1262)· at org.apache.hadoop.hbase.ipc.RpcClientImpl.call(RpcClientImpl.java:1230)· at org.apache.hadoop.hbase.ipc.AbstractRpcClient.callBlockingMethod(AbstractRpcClient.java:213)· at org.apache.hadoop.hbase.ipc.AbstractRpcClient$BlockingRpcChannelImplementation.callBlockingMethod(AbstractRpcClient.java:287)· at org.apache.hadoop.hbase.protobuf.generated.ClientProtos$ClientService$BlockingStub.get(ClientProtos.java:32627)· at org.apache.hadoop.hbase.client.HTable$4.call(HTable.java:881)· at org.apache.hadoop.hbase.client.HTable$4.call(HTable.java:872)· at org.apache.hadoop.hbase.client.RpcRetryingCaller.callWithRetries(RpcRetryingCaller.java:126)· ... 19 more· Caused by: org.apache.hadoop.hbase.ipc.CallTimeoutException: Call id=418960885, waitTime=1200001, operationTimeout=1200000 expired.· at org.apache.hadoop.hbase.ipc.Call.checkAndSetTimeout(Call.java:70)· at org.apache.hadoop.hbase.ipc.RpcClientImpl.call(RpcClientImpl.java:1204)· ... 25 more上面RpcClientImpl的call方法中真正发生作用的是下面这句话。这里callSender其实是一个Thread子类,sendcall只是把call放到其中的blockingqueue中,cts = connection.callSender.sendCall(call, pcrc.getPriority(), Trace.currentSpan());
如下只是offer到queue里面。private class CallSender extends Thread implements Closeable { protected final BlockingQueue<CallFuture> callsToWrite; public CallFuture sendCall(Call call, int priority, Span span) throws InterruptedException, IOException { CallFuture cts = new CallFuture(call, priority, span); if (!callsToWrite.offer(cts)) { throw new IOException("Can't add the call " + call.id + " to the write queue. callsToWrite.size()=" + callsToWrite.size()); } checkIsOpen(); // We check after the put, to be sure that the call we added won't stay // in the list while the cleanup was already done. return cts; }查看一下这个blockingqueue的数据是如何被执行的,如下,可以开始看到根底层socket相关的线索。
public void run() { while (!shouldCloseConnection.get()) { CallFuture cts = null; try { cts = callsToWrite.take(); } catch (InterruptedException e) { markClosed(new InterruptedIOException()); } if (cts == null || cts == CallFuture.DEATH_PILL) { assert shouldCloseConnection.get(); break; } if (cts.call.done) { continue; } if (cts.call.checkAndSetTimeout()) { continue; } try { Connection.this.tracedWriteRequest(cts.call, cts.priority, cts.span); } catch (IOException e) { if (LOG.isDebugEnabled()) { LOG.debug("call write error for call #" + cts.call.id + ", message =" + e.getMessage()); } cts.call.setException(e); markClosed(e); } } cleanup(); }tracedWriteRequest
private void writeRequest(Call call, final int priority, Span span) throws IOException { RequestHeader.Builder builder = RequestHeader.newBuilder(); builder.setCallId(call.id); if (span != null) { builder.setTraceInfo( RPCTInfo.newBuilder().setParentId(span.getSpanId()).setTraceId(span.getTraceId())); } builder.setMethodName(call.md.getName()); builder.setRequestParam(call.param != null); ByteBuffer cellBlock = ipcUtil.buildCellBlock(this.codec, this.compressor, call.cells); if (cellBlock != null) { CellBlockMeta.Builder cellBlockBuilder = CellBlockMeta.newBuilder(); cellBlockBuilder.setLength(cellBlock.limit()); builder.setCellBlockMeta(cellBlockBuilder.build()); } // Only pass priority if there one. Let zero be same as no priority. if (priority != 0) builder.setPriority(priority); RequestHeader header = builder.build(); setupIOstreams();根据HBASE 官方的jira可以知道,1.1版本的hbase中,默认依然采用的是rpcclientimpl版本
AbstractRpcClient.java的子类有两个
asyncrpcclient
rpcclientimpl
https://issues.apache.org/jira/browse/HBASE-12684
0 0
- HBase Client Get 源码分析
- Hbase源码分析之org.apache.hadoop.hbase.client包
- HBase 0.1.0 Get流程源码分析
- HBase源码分析之Client端操作处理
- [httpcomments-client-4.5.2]--源码分析(Get请求)
- Hbase 源码分析4 - Get 流程及rpc原理
- Hbase 源码分析6 -- Regionserver上的 Get 全流程
- Hbase 源码分析四 - Get 流程及rpc原理
- Hbase 源码分析之 Regionserver下的 Get 全流程
- Hbase 源码分析之 Regionserver上的 Get 全流程
- hbase HTable之Put、delete、get等源码分析
- HBase源码分析之org.apache.hadoop.hbase.client.coprocessor包
- neutron client源码分析
- Hbase-0.98.6源码分析--Put写操作Client端流程
- zookeeper源码分析-client分析
- hbase coprocessor 源码分析
- HBase源码分析
- Hbase源码分析 RowCounter
- Apriori算法——关联分析
- PHP中过滤html标签
- live555 安装
- ZCMU-1540-第K大个数
- Zabbix 3.0.5安装GraphTrees
- HBase Client Get 源码分析
- long类型需要注意
- stm8 sttoolset不能编译问题
- php中的html转译
- 【postgis&geoserver】在postgis中建立空间数据库并发布到geoserver
- 高德地图infowindow点击其他地方消失
- 串口通信一般有两种方式: 1、字符 2、字节
- $(function(){})与(function($){})(jQuery)、$(document).ready(function(){})
- 基于Matlab的BP神经网络在语音特征信号识别中的应用