HBase1.0.0源碼分析之Client啟動串連流程,hbase1.0.0client

來源:互聯網
上載者:User

HBase1.0.0源碼分析之Client啟動串連流程,hbase1.0.0client
我們知道在使用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,相關主要類圖如下:

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.