—client –>hmaster 和 client —> regionserver的流程
(源码基于hbase-1.1.5版本)
服务端主要有两个进程,hmaster 和 HRegionServer(其实 hmaster继承于 HRegionServer,这两个进程中既提供了web界面,同时也提供了rpc服务的调用,
如web服务在hmaster中是 http://127.0.0.1:16010/master-status
在regionserver中的web界面是 http://127.0.0.1:16030/rs-status
是通过HRegionServer.putUpWebUI 进行拉起jetty的不同业务的web界面
同时这两个进程也提供rpc服务,
hmaster 和 regionserver 绑定到不同的端口进行rpc ,就是通过 RpcServer 类进行的,在RSRpcServices(MasterRpcServices 是hamster调用的,其实MasterRpcServices也继承于 RSRpcServices) 中进行调用
通过 RpcServer.Listener 的方法,拉起一个nio server线程,来监听客户端的连接。
如
bind(acceptChannel.socket(), bindAddress, backlogLength);
然后在 Listener 线程当中,接收数据请求。
每一个链接都拿一下线程Reader 对象进行处理,创建的线程reader数量是通过(hbase.ipc.server.read.threadpool.size)
参数进行定义的,所以如果想提高线程的处理并发数,可以调整这个参数。
然后每个链接都创建 org.apache.hadoop.hbase.ipc.RpcServer.Connection.Connection
对象到 readKey.attach(c); 中调用 readAndProcess()方法读取连接中的数据
第一次连接上来时,调用readPreamble()方法,读取头部的数据如 AuthMethod.SIMPLE 、version 等头部信息
校验通过后,读取数据到data对象中,调用process()方法进行数据的处理
在数据处理中,会根据刚才的头部中上传的auth信息,进行判断是否进行权限校验。通过 变量 useSasl 保存。
在head部分,就可以拿到上传的用户名称.
接着通过authorizeConnection()方法进行权限的校验,如果校验失败,就返回出错
在
authorize(UserGroupInformation user, ConnectionHeader connection, InetAddress addr)
方法当中,会根据是否配置了HADOOP_SECURITY_AUTHORIZATION 参数进行权限的验证
通过
Class c = getServiceInterface(services, connection.getServiceName());
拿到来源模块的接口方法
this.authManager.authorize(user != null ? user : null, c, getConf(), addr);
在这里进行KerberosInfo 的验证
所以其实Kerberos 的校验,就是通过来源的ip+username进行判断的。
当校验完成后,就调用processRequest()方法进行业务数据的处理了,在RpcServer的创建时,
有传入一个services参数,其实就是下面的方法
protected List<BlockingServiceAndInterface> getServices() {
List<BlockingServiceAndInterface> bssi = new ArrayList<BlockingServiceAndInterface>(2);
bssi.add(new BlockingServiceAndInterface(
ClientService.newReflectiveBlockingService(this),
ClientService.BlockingInterface.class));
bssi.add(new BlockingServiceAndInterface(
AdminService.newReflectiveBlockingService(this),
AdminService.BlockingInterface.class));
return bssi;
}
这个方法,已经包含所有的业务调用了,通过客户端上传的serviceName,拿到对应的模块,然后反射调用对应的方法
再次调用 md = this.service.getDescriptorForType().findMethodByName(header.getMethodName());
就可以找到对应的具体method的调用。
创建call调用对象
Call call = new Call(id, this.service, md, header, param, cellScanner, this, responder,
totalRequestSize, traceInfo, RpcServer.getRemoteIp());
然后放在 用CallRunner包装一下提交在 scheduler 线程池当中,
在CallRunner里面的run方法会调用到 RpcServer.call
resultPair = this.rpcServer.call(call.service, call.md, call.param, call.cellScanner,
call.timestamp, this.status)
在里面隐含着一个比较重要的的对象
RpcServer.CurCall.set(call);
把外面的所有参数放在call的当前线程当中,但是由于这个CurCall是protected的,在具体的方法当中,拿不到。
在业务方法中,为了拿到ip和user的信息,就需要从这个对象中拿出新的信息,
放在PayloadCarryingRpcController 对象,传到下个方法中了
在方法里面
Message result = service.callBlockingMethod(md, controller, param);
调用到service的接口方法,其实就是调用到 RSRpcServices 这个类当中,可以看到这个类的继承关系
RSRpcServices implements HBaseRPCErrorHandler,
AdminService.BlockingInterface, ClientService.BlockingInterface, PriorityFunction;
无论是调用hmaster还是调用hregionserver的rpc服务,都是最后回调到这个类当中。
如调用到 RSRpcServices.scan 方法当中,通过如下代码
String requestUserName = ((PayloadCarryingRpcController)controller).getRequestUserName();
就可以进行 拿到客户端的帐号了