HBase1.0.0源碼分析之Client啓動連接流程

我們知道在使用HBase的過程中首要的是和服務器端取得鏈接,那麼客戶端是如何去鏈接的,它是怎麼找到master和regionserver的? 參與該過程中的主要組件又有哪些?這些組件之間是如何協同工作的呢? 今天就讓我們來一起解析.
HBase的連接代碼很簡單,如下:
try (Connection connection = ConnectionFactory.createConnection(conf))
這裏用到了工廠模式進行Connection實例的創建,需要傳入的是配置參數管理類Configuration,在創建中首先需要把用戶信息添加進去:
 if (user == null) {
      UserProvider provider = UserProvider.instantiate(conf);
      user = provider.getCurrent();
    }

    return createConnection(conf, false, pool, user);

 String className = conf.get(HConnection.HBASE_CLIENT_CONNECTION_IMPL,
      ConnectionManager.HConnectionImplementation.class.getName());
    Class<?> clazz = null;
    try {
      clazz = Class.forName(className);
    } catch (ClassNotFoundException e) {
      throw new IOException(e);
    }
    try {
      // Default HCM#HCI is not accessible; make it so before invoking.
      Constructor<?> constructor =
        clazz.getDeclaredConstructor(Configuration.class,
          boolean.class, ExecutorService.class, User.class);
      constructor.setAccessible(true);
      return (Connection) constructor.newInstance(conf, managed, pool, user);

這裏使用了反射技術進行類對象的構造,從代碼中我們看到實際是調用了HConncetionImplementation的構造函數,這些類之間的相互關係如下圖所示:

從途中可以看出,HConnectionImplementation是實際的Connction實現類,接下來我們去看看該類的實例化過程:

        HConnectionImplementation(Configuration conf, boolean managed,
                                  ExecutorService pool, User user) throws IOException {
            this(conf);
            this.user = user;
            this.batchPool = pool;
            this.managed = managed;
            this.registry = setupRegistry();
            retrieveClusterId();

            this.rpcClient = RpcClientFactory.createClient(this.conf, this.clusterId);
            this.rpcControllerFactory = RpcControllerFactory.instantiate(conf);

            // Do we publish the status?
            boolean shouldListen = conf.getBoolean(HConstants.STATUS_PUBLISHED,
                    HConstants.STATUS_PUBLISHED_DEFAULT);
            Class<? extends ClusterStatusListener.Listener> listenerClass =
                    conf.getClass(ClusterStatusListener.STATUS_LISTENER_CLASS,
                            ClusterStatusListener.DEFAULT_STATUS_LISTENER_CLASS,
                            ClusterStatusListener.Listener.class);
            if (shouldListen) {
                if (listenerClass == null) {
                    LOG.warn(HConstants.STATUS_PUBLISHED + " is true, but " +
                            ClusterStatusListener.STATUS_LISTENER_CLASS + " is not set - not listening status");
                } else {
                    clusterStatusListener = new ClusterStatusListener(
                            new ClusterStatusListener.DeadServerHandler() {
                                @Override
                                public void newDead(ServerName sn) {
                                    clearCaches(sn);
                                    rpcClient.cancelConnections(sn);
                                }
                            }, conf, listenerClass);
                }
            }
        }

好吧這看起來有點小複雜,它首先調用了另一個構造類
        protected HConnectionImplementation(Configuration conf) {
            this.conf = conf;
            this.tableConfig = new TableConfiguration(conf);
            this.closed = false;
            this.pause = conf.getLong(HConstants.HBASE_CLIENT_PAUSE,
                    HConstants.DEFAULT_HBASE_CLIENT_PAUSE);
            this.numTries = tableConfig.getRetriesNumber();
            this.rpcTimeout = conf.getInt(
                    HConstants.HBASE_RPC_TIMEOUT_KEY,
                    HConstants.DEFAULT_HBASE_RPC_TIMEOUT);
            if (conf.getBoolean(CLIENT_NONCES_ENABLED_KEY, true)) {
                synchronized (nonceGeneratorCreateLock) {
                    if (ConnectionManager.nonceGenerator == null) {
                        ConnectionManager.nonceGenerator = new PerClientRandomNonceGenerator();
                    }
                    this.nonceGenerator = ConnectionManager.nonceGenerator;
                }
            } else {
                this.nonceGenerator = new NoNonceGenerator();
            }
            stats = ServerStatisticTracker.create(conf);
            this.asyncProcess = createAsyncProcess(this.conf);
            this.interceptor = (new RetryingCallerInterceptorFactory(conf)).build();
            this.rpcCallerFactory = RpcRetryingCallerFactory.instantiate(conf, interceptor, this.stats);
            this.backoffPolicy = ClientBackoffPolicyFactory.create(conf);
        }
ConnectionManager.nonceGenerator = new PerClientRandomNonceGenerator();//每個客戶端隨機的NonceGEnerator,主要是爲了生成clientid
stats = ServerStatisticTracker.create(conf);創建跟蹤該connection所相關的region 信息監控實例
this.asyncProcess = createAsyncProcess(this.conf);創建一個同步進程實例,該進程主要負責持續的請求流
this.interceptor = (new RetryingCallerInterceptorFactory(conf)).build();//遠程服務器出現故障時,進行處理的機制
this.rpcCallerFactory = RpcRetryingCallerFactory.instantiate(conf, interceptor, this.stats);//RpcRetryingCaller創建工廠

this.backoffPolicy = ClientBackoffPolicyFactory.create(conf);//這個實際沒有具體的的類實現


到此結束了下面的那個構造函數,接下來我們回過頭來看看上面的構造函數的剩餘部分:
同樣的我們也就只是分析一些關鍵步驟:
 this.registry = setupRegistry();//用於獲取集羣的基本信息例如clusterid以及region location的meta數據
this.rpcClient = RpcClientFactory.createClient(this.conf, this.clusterId); //負責IPC調用相關
this.rpcControllerFactory = RpcControllerFactory.instantiate(conf);//
至此客戶端的啓動結束了,這裏其實主要是啓動兩個服務,
一個是用於request處理的AsyncProcess
一個是用於獲取服務器信息的Registry
還有就是負責RPC調用的RpcClient,相關主要類圖如下:

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