hbase服務端源碼分析

—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();

就可以進行 拿到客戶端的帳號了

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