Java basics: SocketChannel and Selector are applied in ZooKeeper
ZooKeeper starts from the main function of the QuorumPeerMain class:
The call sequence is: Main-> initializeAndRun-> runFromConfig
1. Default NIOServerCnxnFactory Communication Method
RunFromConfig mainly does two tasks:
(1) initialize the network communication processing class ServerCnxnFactory between the client and the server:
ServerCnxnFactory cnxnFactory = ServerCnxnFactory. createFactory ();
The internal implementation of the createFactory function is:
if (serverCnxnFactoryName == null) { serverCnxnFactoryName = NIOServerCnxnFactory.class.getName();} try { return(ServerCnxnFactory) Class.forName(serverCnxnFactoryName).newInstance();} catch (Exception e) { IOException ioe = new IOException("Couldn't instantiate " + serverCnxnFactoryName); ioe.initCause(e); throw ioe;}You can see the default initialized
ServerCnxnFactory isNIOServerCnxnFactory, which is a network communication in Java NIO mode. In addition, the NettyServerCnxnFactory class provides the Netty communication mode.
(2) Start QuorumPeer:
QuorumPeer. start ();
The start function of the initialized ServerCnxnFactory class is called internally:
CnxnFactory. start ();
Ii. NIOServerCnxnFactory. start () method
@ Override publicvoidstart () {stopped = false; if (workerPool = null) {workerPool = new WorkerService ("NIOWorker", numWorkerThreads, false );} // start a bunch of selector threads for (SelectorThread thread: selectorThreads) {if (thread. getState () = Thread. state. NEW) {thread. start () ;}// restart the accept thread if (acceptThread. getState () = Thread. state. NEW) {acceptThread. start () ;}// finally start the expire thread if (expirerThread. getState () = Thread. state. NEW) {expirerThread. start ();}}Iii. Relationship between several thread classes in NIOServerCnxnFactory
NIOServerCnxnFactory contains three classes:
(1) AbstractSelectThread: The common parent class of the SelectorThread class and the AcceptThread class maintainsSelector object.
(2) AcceptThread: Manage new ZooKeeper client connection requests. In fact, the selector of the parent class is used to listen to the"SelectionKey. OP_ACCEPT"Event. Once a new request is sent, it is responsible for establishing a SocketChannel connection with the client, allocating a thread from the SelectorThread thread pool, and placing the SocketChannel connection into the acceptedQueue queue maintained by the SelectorThread thread.
(3) SelectorThread: Listen to the data read/write events on the established SocketChannel connection allocated by the AcceptThread, and execute the actual data read/write. The selector of the parent class is used to listen toAcceptedQueueA data read/write event established in the queue. Once a read/write event occurs, the handleIO function is called to process the read/write request.
The initialization of selectorThreads is as follows:
For (inti = 0; I
The initialization of the new connection management thread acceptThread is as follows:
this.ss =ServerSocketChannel.open();ss.socket().setReuseAddress(true);LOG.info("binding to port " + addr);ss.socket().bind(addr);ss.configureBlocking(false);acceptThread= newAcceptThread(ss, addr, selectorThreads);
Then NIOServerCnxnFactory. start () will start these threads.
AcceptThreadThe run function is very simple, that is, listening to the SelectionKey. op_accept event, then establishing a SocketChannel connection, and allocating a SelectorThread to process the connection, which is not detailed in detail.
SelectorThreadThe core of the run function is to listen to the SelectionKey. OP_READ event and then execute the handleIO function. The details of how to implement a data interaction plan with the client are described in other articles.