The reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers.
The Reactor pattern is also called the reactor design pattern and is a An event design pattern for processing service requests submitted concurrently to one or more service handlers. When requests arrive, these requests are demultiplexed and distributed to the corresponding request processors through the service processor. The Reactor pattern is mainly composed of two core parts: Reactor and Handler, as shown in the figure below. They are responsible for the following things:
#Reactor: Responsible for monitoring and distributing events, event types Contains connection events, read and write events;
Handler: responsible for processing events, such as read -> business logic (decode compute encode) -> send;
In most scenarios, processing a network request has the following steps:
① read: read data from the socket.
② decode: Decoding, data on the network are transmitted in the form of bytes. To obtain the real request, you must decode
③ compute: calculation, that is, business processing.
④ encode: Encoding, data on the network is transmitted in the form of bytes, that is, the socket only receives bytes, so encoding is required.
⑤ send: Send response data
For Reactor mode, whenever an Event is input to the Server, the Service Handler will forward it (dispatch) The corresponding Handler is processed. Three roles defined in the Reactor model:
The Reactor is responsible for monitoring and distributing events, and dispatching them to the corresponding Handlers.. New events include connection establishment ready, read ready, write ready, etc.
Acceptor: Request the connector to handle new client connections. After Reactor receives the connection event from the client, it forwards it to Acceptor, which receives the Client's connection, creates the corresponding Handler, and registers this Handler with Reactor.
Handler: Request processor, responsible for event processing, binding itself to the event, performing non-blocking read/write tasks, completing channel reading, and writing the results out of the channel after completing the processing of business logic. . Available resource pools can be managed.
The model is roughly as shown in the figure below:
For read/write requests, the Reactor model is processed according to the following process:
(1) The application registers the read/write ready event and the associated event handler
(2) The event demultiplexer waits for the occurrence of the event
(3) When a read/write readiness event occurs, the event separator calls the event handler registered in the first step
Reactor The Reactor in the model can be single or multiple, and the Handler can also be single-threaded or multi-threaded, so there are roughly three combination modes:
Single Reactor single-thread model
Single Reactor multi-thread model
Master-slave Reactor single-thread model
Master-slave Reactor multi-thread model
The third master-slave Reactor single-thread model has no practical significance, so the following will focus on the other three Model
(1) Reactor thread listens through select Event, after receiving the event, distribute it through Dispatch
(2) If it is a connection establishment event, the event will be distributed to the Acceptor. The Acceptor will obtain the connection through the accept() method and create a Handler object to handle the subsequent The response event
(3) If it is an IO read and write event, the Reactor will hand over the event to the currently connected Handler for processing
(4) The Handler will complete the read -> business Processing -> complete business process of send
The advantage of the single-Reactor single-thread model is that all processing logic is implemented in one thread, and there are no multi-threads or processes. Communication and competition issues. However, this model has serious problems in terms of performance and reliability:
① Performance: Only components are distinguished in the code. The overall operation is still single-threaded, which cannot fully utilize CPU resources. Moreover, the Handler business processing part is not asynchronous. A Reactor must be responsible for processing connection requests. It is also responsible for processing read and write requests. Generally speaking, processing connection requests is very fast, but processing read and write requests involves business logic processing, which is relatively slow. Since Reactor processes read and write requests, other requests will be blocked, which can easily lead to system performance bottlenecks
② Reliability: Once the Reactor thread is interrupted unexpectedly or enters an infinite loop, it will As a result, the entire system communication module is unavailable and cannot receive and process external messages, causing node failure.
Therefore, the single-Reactor single-process model is not suitable for computing-intensive scenarios and is only suitable for business Handle very fast scenarios. The threading model of Redis is implemented based on the single Reactor single-thread model. Because Redis business processing is mainly completed in memory, the operation speed is very fast, and the performance bottleneck is not on the CPU, so Redis processes commands in a single process.
In order to solve the performance problems of the single Reactor single-thread model, the single-Reactor multi-thread model has evolved, which is used in the event processor part. Multi-threading (thread pool)
(1) The Reactor thread listens for events through select and proceeds through Dispatch after receiving the event Distribution
(2) If it is a connection establishment event, the event is distributed to the Acceptor. The Acceptor will obtain the connection through the accept() method and create a Handler object to handle subsequent response events
(3) If it is an IO read and write event, the Reactor will hand over the event to the Handler corresponding to the current connection for processing
(4) Unlike a single Reactor single thread, the Handler no longer does specific business processing , is only responsible for receiving and responding to events. After receiving data through read, the data is sent to the subsequent Worker thread pool for business processing.
(5) The Worker thread pool allocates threads for business processing. After completion, the response results are sent to the Handler for processing.
(6) After receiving the response result, the Handler returns the response result to the Client through send.
Compared with the first model, after processing the business logic, that is, after obtaining the IO read and write events, it is handed over to the thread pool for processing, and the Handler collects After receiving the response, the response result is returned to the client through send. This can reduce the performance overhead of Reactor, allowing it to focus more on event distribution and improve the throughput of the entire application. Moreover, the Handler uses multi-threading mode to fully utilize the CPU performance. However, there are problems with this model:
(1) Handler uses multi-thread mode, which naturally brings the overhead of multi-thread competition for resources. It also involves mutual exclusion and protection mechanisms for shared data, making the implementation more complicated
(2) A single Reactor is responsible for monitoring, distributing and responding to all events, which can easily cause performance bottlenecks in high-concurrency scenarios.
The single Reactor multi-thread model solves the single-thread performance problem of Handler, but the Reactor is still single-threaded and will still have performance for high concurrency scenarios. bottleneck, so Reactor needs to be adjusted to multi-threading mode, which is the master-slave Reactor multi-threading model to be introduced next. In the master-slave Reactor multi-threading model, the Reactor is divided into two parts
(1) MainReactor: only responsible for processing connection establishment events, listening to the server socket through select, and registering the established socketChannel to the subReactor. Usually One thread is enough
(2) SubReactor: Responsible for reading and writing events, maintaining its own selector, performing multi-channel separation of IO reading and writing events based on the SocketChannel registered by MainReactor, reading and writing network data, and handing over business processing This is done by the worker thread pool. The number of SubReactors is generally the same as the number of CPUs
(1) The MainReactor object in the main thread listens to events through select. After receiving the event, it is distributed through Dispatch. If the event type is a connection establishment event, it is distributed to the Acceptor for connection establishment.
Connection establishment:
① Randomly select a Reactor thread from the main thread pool as the Acceptor thread to bind the listening port and receive client connections
② The Acceptor thread creates a new SocketChannel after receiving the client connection request, and registers it to the main thread pool On other Reactor threads, it is responsible for access authentication, IP black and white list filtering, handshake and other operations.
③ After step ② is completed, the link of the business layer is officially established. Remove the SocketChannel from the multiplexer of the Reactor thread in the main thread pool, re-register it to the thread of the SubReactor thread pool, and create a Handler. Used to handle various connection events
(2) If the received event is not a connection establishment event, it is distributed to SubReactor, and SubReactor calls the Handler corresponding to the current connection for processing
(3) Handler passes read After reading the data, distribute the data to the Worker thread pool for business processing, and the Worker thread pool allocates threads for business processing. After completion, the response result is sent to Handler
(4) Handler passes the response result after receiving it. send returns the response result to Client
The advantage of the master-slave Reactor multi-thread model is that the main thread and sub-threads have a clear division of labor. The main thread is only responsible for receiving new connections, and the sub-threads It is responsible for completing subsequent business processing. At the same time, the interaction between the main thread and the sub-thread is also very simple. After the sub-thread receives the connection from the main thread, it only needs to process the business. There is no need to pay attention to the main thread. The processing results can be sent directly to the client in the sub-thread. .
This Reactor model is suitable for high concurrency scenarios, and the Netty network communication framework also adopts this implementation.
(1) Fast response, no need to Blocked by a single synchronization time, although Reactor itself is still synchronized;
(2) can avoid complex multi-threading and synchronization issues to the greatest extent, and avoid multi-thread/process switching overhead
(3) Scalability, you can easily make full use of CPU resources by increasing the number of Reactor instances;
(4) Reusability, the Reactor model itself has nothing to do with specific event processing logic, and has Very high reusability.
The above is the detailed content of What is the concept of Reactor network model in Java IO. For more information, please follow other related articles on the PHP Chinese website!