web123456

Notes on the fifth issue of Java Architect of Turing College

origin
Watched a few days agonettyThe working principle is very incomprehensible to netty's thread model. After checking a lot of information, I finally got some insights. This is recorded for reference.

Reading object
in nettyNIOprogrammingModelIt is based on Java Nio encapsulation, so readers need to have a certain understanding of Java NIO. Due to space limitations, this article will not give a detailed description of NIO. Readers in need can view the detailed explanation of JAVA BIO, NIO, AIO (with code implementation) and the introduction of Netty

Netty's NIO threading model
Before talking about netty's threading model, let's talk about the key codes in the way traditional NIO is used.

You can see that after the current thread has obtained the client connection, registers the channel to the selector again, and registers the event as read, so that the message can be read. That is to say, obtaintcpConnecting and reading messages are processed in the same thread. So what's wrong with this method? For some small traffic application scenarios, a single threaded model can be used. But for high loads, largeconcurrentThe application scenarios are not suitable, the main reasons are as follows:


A NIO thread processes hundreds of links simultaneously.performanceThe NIO thread cannot support it. Even if the CPU load of the NIO thread reaches 100%, it cannot meet the encoding, decoding, reading and sending of massive messages;
When the NIO thread is overloaded, the processing speed will slow down, which will cause a large number of client connections to time out, and retransmission will often occur after the timeout, which will heavier the load of the NIO thread, and will eventually lead to a large number of message backlogs and processing timeouts, becoming a performance bottleneck of the system;
Reliability issue: Once the NIO thread accidentally runs away or enters a dead loop, it will cause the entire system communication module to be unavailable, unable to receive and process external messages, causing node failure.

Then you may think, since a thread cannot work, isn't it enough for me to use a thread pool when reading messages? It's really feasible, and in fact, it's really done in Netty.

A startup program for netty is as follows

You can see that two EventLoopGroups are new at the beginning, and EventLoopGroup can be temporarily understood as a thread group. Among them, bossGroup is responsible for handling the client's TCP connection request. If the system has only one server port to listen, it is recommended that the bossGroup thread group number is set to 1. WorkerGroup is the thread group that is truly responsible for I/O read and write operations.

First look at a netty execution flow chart

In the figure, you can see that boosGroup will be re-registered to the workerGroup after receiving the request, which corresponds to the bossGroup mentioned above, which is responsible for handling the client's TCP connection request, and workerGroup is the thread group that is truly responsible for I/O read and write operations. Just likeSoftware DevelopmentThe boss inside is responsible for assigning tasks, while the worker is the programmer who writes the code. So how does bossGroup handle tcp's connection request and register it with workerGroup at the same time?

How does bossGroup assign tasks
Each thread in the workerGroup has a multiplexer Selector. Every time the bossGroup receives a client connection, it will select a thread from the workerGroup and register the channel to its Selector.

Pseudocode implementation

Code in boss

You can see that after the bossGroup receives the request from the new client, it will call aalgorithm, select a worker from multiple workers, and then call the worker registration method to register the channel of this new client. Let's look at the registration method implementation in workerGroup

You can see that the new channel is registered with your Selector. After registration, the workerGroup will be blocked. In this way, the thread in the workerGroup will start to read data. Let’s take a look at the pseudo-code implementation of the worker thread to read data (in fact, it is the way to read data in ordinary NIO)

Summary: The bossGroup is responsible for handling the client's TCP connection request. Every time the bossGroup receives a client connection, it will select a thread from the workerGroup and register the channel to its Selector. In this way, the request reception and request processing are separated by different threads, which is also one of the reasons why netty is efficient. Of course, the reason why Netty is efficient is not only due to the excellent threading model design, but also closely related to Netty's coding protocol, virtual buffer, and Zero-Copy (zero copy).