Hbase的RPC主要由HBaseRPC、RpcEngine、HBaseClient、HBaseServer、VersionedProtocol 5个概念组成。
1、HBaseRPC是hbase RPC的实现类,核心方法:
1)、RpcEngine getProtocolEngine():返回RpcEngine对象
2)、<T extends VersionedProtocol> T waitForProxy():调用RpcEngine的getProxy()方法,返回一个远程代理对象,比如:第一次访问HRegionServer时需要执行该方法,设置代理后,会缓存该对象到HConnectionImplementation中。
2、RpcEngine接口,其实现类:WritableRpcEngine,核心方法:
1)、VersionedProtocol getProxy():返回代理对象,HRegionServer和HMaster均是VersionedProtocol的实现类,即返回的对象可代理执行HRegionServer和HMaster的方法;
2)、Object[] call():调用程序接口,最终是经过HBaseClient的内部类Connection通过socket方式完成;
3)、RpcServer getServer():返回RpcServer的实现类,有一个抽象实现: HBaseServer和HBaseServer的子类:WritableRpcEngine.Server。
4)、stopProxy()
3、HBaseClient:RPC的client端实现,最核心的方法是call(),通过该方法可执行服务端的方法,该类中有一个重要的内部类:HBaseClient.Connection,该类封装了socket,具体原理就是把要执行的方法通过socket告诉服务端,服务端通过HBaseServer类从socket中读出client端的调用方法,然后执行相关类的相应方法,结果再通过socket传回。
4、HBaseServer:RPC的server端实现,HBaseServer有两个重要的内部类,一个是HBaseServer.Connection,另一个是Handler类,这里的Connection从socket中读出call方法并放入callQueue队列中,Handler类从该队列中取出call方法(比如:scan查询时执行的一次next(),该方法会执行到服务端HRegionServer的next(),这里next就是call方法)并执行,结果通过socket输出给client端,Handler是Thread的子类,在RS启动时就会创建所有的Handle线程,然后一直执行,具体的handler线程数可以通过配置项hbase.regionserver.handler.count配置,默认是10。
5、VersionedProtocol,该接口的类图如下:
可进行RPC调用的类必须是该接口的实现类,hbase client、 RS、Master相互之间的访问总结为:
- HBase Client 通过HMasterInterface接口访问HMasterServer,通过HRegionInterface接口访问HRegionServer;
- HRegionServer通过HMasterRegionInterface接口访问HMasterServer;
- HMaster通过HRegionInterface接口访问HRegionServer,在访问RS时Master就是HBase Client的角色。
以scan查询为例画时序图,通过时序图详细理解HBase的RPC调用过程
关于HBase的RPC一些知识补充如下:
1、HBaseClient缓存了HBaseClient.Connection,默认一个client应用与每个RS均只有一个socket链接,可以通过以下两个配置项修改:
1)、hbase.client.ipc.pool.type:默认为RoundRobin,共三种,如下:
// PoolMap类的createPool方法,在HBaseClient缓存connection时会调用,从pool中获取connection时,如果缓存的数量没有达到poolMaxSize,则会返回null,从而创建新的connection对象 protected Pool<V> createPool() { switch (poolType) { case Reusable: return new ReusablePool<V>(poolMaxSize); //复用的池 case RoundRobin: return new RoundRobinPool<V>(poolMaxSize); //轮询 case ThreadLocal: return new ThreadLocalPool<V>(); //本地线程 } return null; } //PoolMap.RoundRobinPool类的get方法,缓存的数量没有达到poolMaxSize,则会返回null,这时会创建新的 |