HBase1.0.0 source code analysis-Client startup connection process, hbase1.0.0client
We know that in the process of using HBase, the first thing to do is to get a link with the server, so how does the client link, how does it find the master and regionserver? What are the main components involved in this process? How do these components work together? Let's resolve it together today.
The connection code of HBase is as follows:
try (Connection connection = ConnectionFactory.createConnection(conf))
The factory mode is used to create a Connection instance. You need to input the Configuration parameter management Configuration. In the creation process, you must first add the user information:
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);
The reflection technology is used to construct class objects. From the code, we can see that the conncetionimplementation constructor is called. The relationships between these classes are shown in:
We can see from the process that HConnectionImplementation is the actual Connction implementation class. Next we will look at the instantiation process of this class:
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); } } }
Okay, it looks a little complicated. It first calls another constructor class.
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 (); // random NonceGEnerator for each client, mainly to generate clientid
Stats = ServerStatisticTracker. create (conf); create a region information monitoring instance that tracks the connection
This. asyncProcess = createAsyncProcess (this. conf); creates a synchronization process instance, which is mainly responsible for continuous request streams.
This. interceptor = (new RetryingCallerInterceptorFactory (conf). build (); // mechanism for processing when a remote server fails
This. rpcCallerFactory = RpcRetryingCallerFactory. instantiate (conf, interceptor, this. stats); // RpcRetryingCaller creates a factory
This. backoffPolicy = ClientBackoffPolicyFactory. create (conf); // there is no actual class implementation.
At this point, the following constructor is ended. Next, let's look at the remaining parts of the constructor above:
Similarly, we only analyze some key steps:
This. registry = setupRegistry (); // obtains the basic information of the cluster, such as the meta data of clusterid and region location.
This. rpcClient = RpcClientFactory. createClient (this. conf, this. clusterId); // responsible for calling IPC
This. rpcControllerFactory = RpcControllerFactory. instantiate (conf );//
At this point, the client has been started. In fact, we mainly start two services,
One is AsyncProcess for request processing.
One is the Registry used to obtain server information.
There is also the RpcClient responsible for RPC calls. The main class diagrams are as follows: