Reactor (Dead Knock 2)

Source: Internet
Author: User

"Text" Netty Source dead Knock 2:

The legendary God-like reactor reactor pattern

Directory of this document

1. Why is the reactor mode
2. Introduction to the reactor model
3. Fatal flaw of multi-threaded IO
4. Single Thread reactor model
4.1. What is single thread reactor?
4.2. Reference code for single-threaded reactor
4.3. Disadvantages of single threading mode:
5. Multi-threaded reactor
5.1. Thread pool-based improvements
5.2. Improved integrity
5.3. Multi-threaded reactor reference code
6. Reactor Continuous Improvement
7. Advantages and disadvantages of reactor programming
7.1. Advantages
7.2. Disadvantages


1. Why is reactor mode

The brothers who write more code know that Java code, because of the interface and high abstraction everywhere, uses the inheritance polymorphism and the design pattern, the organization of the program is not in accordance with the normal order of understanding, the code tracking is a problem. Therefore, in the reading of other people's source code, if you do not understand the organization of the way, often is disoriented, do not know where. Especially when it comes to reading classic code.

Conversely, if you first understand the code design patterns, and then go to code, you will read very easy, not so difficult to understand.

Like Netty such a boutique in the best, certainly also need to start from the design mode. Netty's overall architecture is based on a well-known pattern--reactor model. Reactor mode is a must-know mode for high-performance network programming.

First familiar with reactor mode, must be ax.

2. Reactor Mode Introduction

Netty is a typical reactor model structure, with a detailed explanation of reactor, this article stands on the shoulders of giants, with the reactor pattern described in the "scalable IO in Java" of Doug Lea (the one who is so admired).

The address of "scalable IO in Java" is:http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf

Reactor mode is also called reactor mode, most IO-related components such as Netty, Redis in the use of IO mode, why this mode is needed, how is it designed to solve high-performance concurrency?

3. the fatal flaw of multi-threaded IO

The most primitive network programming idea is the server with a while loop, constantly listen to the port whether there is a new socket connection, if there is, then call a processing function processing, similar to:

while (true) {socket = accept (); handle (SOCKET)}

The biggest problem with this approach is that it cannot be concurrent and inefficient, and if the current request is not processed, the subsequent requests can only be blocked and the throughput of the server is too low.

Then, thinking of using multi-threading, which is the classic connection per thread, each connection is handled with a thread, similar to:

Package Com.crazymakercircle.iodemo.base;import Com.crazymakercircle.config.systemconfig;import Java.io.ioexception;import Java.net.serversocket;import Java.net.socket;class BasicModel implements Runnable {public void run () {try {serversocket ss = new ServerSocket (systemconfig.socket_server_port            ); while (!            Thread.interrupted ()) New Thread (New Handler (Ss.accept ())). Start (); Create a new thread handle//or, single-threaded, or a thread pool} catch (IOException ex) {/* ... */}} s        Tatic class Handler implements Runnable {final socket socket;        Handler (socket s) {socket = s;}                public void Run () {try {byte[] input = new Byte[systemconfig.input_size];                Socket.getinputstream (). read (input);                byte[] Output = process (input);            Socket.getoutputstream (). write (output); } catch (IOException ex) {/* ... */}        } private byte[] process (byte[] input) {byte[] output=null;        /* ... */return output; }    }}

Each request is distributed to a single thread, each of which processes the process on its own.

The previous version of the Tomcat server was actually implemented this way.

multithreaded concurrency mode, one of the advantages of connecting a thread is:

This greatly improves the throughput of the server, because previous requests do not affect subsequent requests after read blocking because they are in different threads. This is why the "one thread can only correspond to a single socket" is often said to be the reason. Another question is, if there is more than one socket connection in a thread? Syntactically yes, but actually no use, each socket is blocked, so in a thread can only handle a socket, even if the accept more than the useless, the previous socket is blocked, the back is not executed to.

multithreaded concurrency mode, one of the disadvantages of connecting a thread is:

The disadvantage is that the resource requirements are too high, the system creates threads that require relatively high system resources, and if the number of connections is too high, the system cannot afford it, and the repeated creation of threads-destruction also takes a price.

The improvement method is:

With event-driven design, the processor is called for data processing when an event is triggered. Using reactor mode, the number of threads is controlled, and a thread handles a large number of events.

4. single thread reactor model


A simple prototype of the reactor model

The selector network communication of the NIO mode in Java is actually a simple reactor model. Can be said to be a simple prototype of the reactor model.

Static class Server {public static void TestServer () throws IOException {//1, get selector selector            Selector Selector = Selector.open ();            2, obtain the channel Serversocketchannel Serversocketchannel = Serversocketchannel.open ();            3. Set to non-blocking serversocketchannel.configureblocking (false);            4, binding connection Serversocketchannel.bind (new Inetsocketaddress (Systemconfig.socket_server_port));            5, register the channel to the selector, and register the operation is: "Receive" Operation Serversocketchannel.register (selector, selectionkey.op_accept); 6, using the polling method, query get "ready" registered operation while (Selector.select () > 0) {//7, get all registered in the current selector selection Option ("Ready to operate") Iterator<Selectionkey> Selectedkeys = Selector.selectedkeys (). iterator (); while (Selectedkeys.hasnext ()) {//8, get "Ready" time Selectionkey Select                    Edkey = Selectedkeys.next (); 9, determine what the key is specific what event if (selectedkey.isacceptable ()) {//10, if connected                        The event that is received is a "receive ready" operation, obtaining a client connection Socketchannel Socketchannel = Serversocketchannel.accept ();                        11, switch to non-blocking mode socketchannel.configureblocking (false);                    12, the channel is registered to the selector selector Socketchannel.register (selector, selectionkey.op_read); } else if (Selectedkey.isreadable ()) {//13), get "read ready" on the selector                        The channel of the state socketchannel Socketchannel = (socketchannel) selectedkey.channel (); 14. Read Data Bytebuffer bYtebuffer = bytebuffer.allocate (1024);                        int length = 0; while (length = Socketchannel.read (bytebuffer))! =-1) {Bytebuffer.fli                            P ();                            System.out.println (New String (Bytebuffer.array (), 0, length));                        Bytebuffer.clear ();                    } socketchannel.close ();                }//15, remove Selection key selectedkeys.remove ();        }}//7, close connection serversocketchannel.close ();        } public static void Main (string[] args) throws IOException {testserver (); }    }


The actual reactor pattern is based on Java NIO, which, on his basis, abstracts out two components--reactor and handler two components:

(1) Reactor: Responsible for responding to IO events, when a new event is detected, send it to the appropriate handler to process; The new event contains the connection is ready, read ready, write ready, and so on.

(2) Handler: Bind itself (Handler) with the event, take charge of the event processing, complete the channel reading, Complete processing business logic, responsible for writing the results of the channel.


4.1. What is single thread reactor?


As shown in the following:

This is the simplest single reactor one-thread model. The reactor thread is a versatile, responsible for multiplexing sockets, accept new connections, and dispatch requests to the handler processor.

The following figure, from the "Scalable IO in Java", is similar to the meaning of the above figure. Reactor and hander are executed in one thread.

By the way, Accepter can be regarded as a special kind of handler.


4.2. reference code for single thread reactor

"Scalable IO in Java", implementation of a single-threaded reactor reference code, reactor code is as follows:


Package Com.crazymakercircle.reactormodel;import Java.io.ioexception;import Java.net.inetsocketaddress;import Java.nio.bytebuffer;import Java.nio.channels.selectionkey;import Java.nio.channels.selector;import Java.nio.channels.serversocketchannel;import Java.nio.channels.socketchannel;import Java.util.Iterator;import    Java.util.set;class Reactor implements runnable{final Selector Selector;    Final Serversocketchannel ServerSocket;        Reactor (int port) throws IOException {//reactor Initialize selector = Selector.open ();        ServerSocket = Serversocketchannel.open ();        Serversocket.socket (). bind (New Inetsocketaddress (port));        Non-blocking serversocket.configureblocking (false);        Step processing, first step, receive accept event Selectionkey SK = Serversocket.register (selector, selectionkey.op_accept);    Attach callback object, acceptor Sk.attach (New acceptor ()); } public void Run () {try {while (!  Thread.interrupted ())          {Selector.select ();                Set selected = Selector.selectedkeys ();                Iterator it = Selected.iterator (); while (It.hasnext ()) {//reactor is responsible for dispatch received event dispatch (Selectionke                Y) (It.next ()));            } selected.clear (); }} catch (IOException ex) {/* ... */}} void Dispatch (Selectionkey k) {Runnable r = (Run        nable) (K.attachment ());        Call the previously registered callback object if (r! = null) {R.run ();            }}//Inner class class Acceptor implements Runnable {public void run () {try                {Socketchannel channel = serversocket.accept ();            if (channel! = NULL) New Handler (selector, channel); } catch (IOException ex) {/* ... */}}}}


The code for handler is as follows:


Package Com.crazymakercircle.reactormodel;import Com.crazymakercircle.config.systemconfig;import Java.io.ioexception;import Java.nio.bytebuffer;import Java.nio.channels.selectionkey;import Java.nio.channels.selector;import Java.nio.channels.socketchannel;class Handler implements runnable{final    Socketchannel Channel;    Final Selectionkey SK;    Bytebuffer input = bytebuffer.allocate (systemconfig.input_size);    Bytebuffer output = Bytebuffer.allocate (systemconfig.send_size);    static final int READING = 0, sending = 1;    int state = READING;        Handler (Selector Selector, Socketchannel c) throws IOException {channel = C;        C.configureblocking (FALSE);        Optionally try first read now SK = Channel.register (selector, 0);        The handler is used as the callback object Sk.attach (this);        The second step is to register the READ ready event Sk.interestops (Selectionkey.op_read);    Selector.wakeup ();    } Boolean Inputiscomplete () {/* ... */return false; } BooLean Outputiscomplete () {/* ... */return false;    } void Process () {/* ... */return;            public void Run () {try {if (state = = READING) {read ();            } else if (state = = sending) {send (); }} catch (IOException ex) {/* ... */}} void Read () throws IOException {Channel.read (INP        UT);            if (Inputiscomplete ()) {process ();            state = sending;        Normally also do first write now//third step, receive write Ready event Sk.interestops (Selectionkey.op_write);        }} void Send () throws IOException {channel.write (output);        When the write is finished, close select Key if (Outputiscomplete ()) {sk.cancel (); }    }}


These two pieces of code are built on the basis of Java NIO, and these two code recommendations must be read. You can see the source code in the IDE, so that the intuitive feel better.

If the seletor of NIO is not fully understood and affects the above code reading, read the Java NiO dead-knock article in the Crazy Creator circle.


4.3. Disadvantages of single threading mode:

1, when one of the handler block, will cause all the other client handler are not executed, and more seriously, the handler block will also cause the entire service can not receive new client requests (because Acceptor is also blocked). Because there are so many flaws, the single-threaded reactor model is less used. This single-threaded model does not take full advantage of multicore resources, so it does not actually use much.

2. Therefore, the single-threaded model is only suitable for scenarios where the business processing components in handler can be completed quickly.


5. Multi-threaded reactor 5.1. improvement based on thread pool

On the basis of thread reactor mode, the following improvements are made:

(1) The execution of the handler processor into the thread pool, multithreading for business processing.

(2) and for reactor, it can still be a single thread. If the server is a multi-core CPU, to take full advantage of system resources, you can split the reactor into two threads.

A simple diagram is as follows:

5.2. the improved complete

The following figure, from the "Scalable IO in Java", and the above figure meaning, almost, just more detailed. Reactor is a separate thread and hander is executed in the thread pool.


5.3. reference code for multithreaded reactor

"Scalable IO in Java", the reference code for multithreaded reactor, is based on a single thread to make a thread pool improvement, the improved handler code is as follows:


Package Com.crazymakercircle.reactormodel;import Com.crazymakercircle.config.systemconfig;import Java.io.ioexception;import Java.nio.bytebuffer;import Java.nio.channels.selectionkey;import Java.nio.channels.selector;import Java.nio.channels.socketchannel;import Java.util.concurrent.ExecutorService;    Import Java.util.concurrent.executors;class Mthreadhandler implements runnable{final Socketchannel channel;    Final Selectionkey Selectionkey;    Bytebuffer input = bytebuffer.allocate (systemconfig.input_size);    Bytebuffer output = Bytebuffer.allocate (systemconfig.send_size);    static final int READING = 0, sending = 1;    int state = READING;    Executorservice pool = Executors.newfixedthreadpool (2);    static final int processing = 3;        Mthreadhandler (Selector Selector, Socketchannel c) throws IOException {channel = C;        C.configureblocking (FALSE);        Optionally try first read now Selectionkey = channel.register (selector, 0); Use handler as CallbacK Object Selectionkey.attach (this);        The second step is to register the READ ready event Selectionkey.interestops (Selectionkey.op_read);    Selector.wakeup ();    } Boolean Inputiscomplete () {/* ... */return false;    } Boolean Outputiscomplete () {/* ... */return false;    } void Process () {/* ... */return;            public void Run () {try {if (state = = READING) {read ();            } else if (state = = sending) {send (); }} catch (IOException ex) {/* ... */}} synchronized void Read () throws IOException {//        ... channel.read (input);            if (Inputiscomplete ()) {state = processing;        Executes pool.execute asynchronously using the thread pool (new Processer ());        }} void Send () throws IOException {channel.write (output); When the write is finished, close the Select key if (OutputiScomplete ()) {selectionkey.cancel ();        }} synchronized void Processandhandoff () {process ();        state = sending;    or rebind attachment//process finish, start waiting for WRITE ready Selectionkey.interestops (Selectionkey.op_write);        } class Processer implements Runnable {public void run () {Processandhandoff (); }    }}


The Reactor class has no major changes, refer to the preceding code.

6. Reactor Continuous Improvement

For multiple CPU machines, the reactor is split into two parts to make full use of system resources. The code is as follows:


Package Com.crazymakercircle.reactormodel;import Java.io.ioexception;import Java.net.inetsocketaddress;import Java.net.socket;import Java.nio.channels.selectionkey;import Java.nio.channels.selector;import Java.nio.channels.serversocketchannel;import Java.nio.channels.socketchannel;import Java.util.Iterator;import Java.util.set;class Mthreadreactor implements runnable{//subreactors collection, one Selector for a subreactor selector[] Selecto    Rs=new selector[2];    int next = 0;    Final Serversocketchannel ServerSocket;        Mthreadreactor (int port) throws IOException {//reactor initialize Selectors[0]=selector.open ();        Selectors[1]= Selector.open ();        ServerSocket = Serversocketchannel.open ();        Serversocket.socket (). bind (New Inetsocketaddress (port));        Non-blocking serversocket.configureblocking (false); Step processing, first step, receive accept event Selectionkey SK = Serversocket.register (selectors[0], selectionkey.op_accept)        ; Attach callback object, Acceptor Sk.attach (New acceptor ()); } public void Run () {try {while (!  Thread.interrupted ()) {for (int i = 0; i<  2;                    i++) {selectors[i].select ();                    Set selected = Selectors[i].selectedkeys ();                    Iterator it = Selected.iterator (); while (It.hasnext ()) {//reactor is responsible for dispatch received events dispatch ( (Selectionkey)                    (It.next ()));                } selected.clear (); }}} catch (IOException ex) {/* ... */}} void Dispatch (Selectionkey k) {Runn        Able R = (Runnable) (K.attachment ());        Call the previously registered callback object if (r! = null) {R.run (); }} class Acceptor {//... public synchronized void run () throws IOException {Socketchann El connection = Serversocket.accept (); The main selector is responsible for the Accept if (connection! = null) {new Handler (Selectors[next], connection ); Pick a subreactor to take care of the receipt.Connection} if (++next = = selectors.length) Next = 0; }    }}


7. advantages and disadvantages of reactor programming 6.1. Advantages

1) Fast response, do not have to be blocked for a single synchronization time, although the reactor itself is still synchronous;

2) programming is relatively simple, can avoid complex multi-threaded and synchronization problems, and avoid multi-threaded/process switching overhead;

3) scalability, can be easily by increasing the number of reactor instances to make full use of CPU resources;

4) reusability, the reactor framework itself is independent of the specific event handling logic and has high reusability;

6.2. Disadvantages

1) compared with the traditional simple model, reactor adds some complexity, so it has a certain threshold and is not easy to debug.

2) reactor mode requires the underlying synchronous event demultiplexer support, such as selector support in Java, operating system select system call support, if you want to implement synchronous event Demultiplexer may not be that efficient.

3) The reactor mode is implemented in the same thread when IO reads and writes data, and even if multiple reactor mechanisms are used, those sharing a reactor channel if there is a long period of data read and write, will affect the corresponding time of the other channel in this reactor, such as when large file transfer, IO operation will affect the corresponding time of other clients, so for this operation, using the traditional thread-per-connection may be a better choice, Or use an improved version of the reactor mode, such as Proactor mode.


Before opening the Netty source code, the above classic codes, must understand Oh!


Crazy Creator Circle:


Crazy Creator Circle: If Java is a martial arts, here gathered a group of martial fetish, exchange programming experience
QQ Group Link: Crazy create customer Circle QQ Group


No programming does not create a customer, no case study. You must remember to run a running case!


Reactor (Dead Knock 2)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.