preface

You learned about Netty in the previous SpringBoot article on integrating long-connection heartbeat mechanisms.

But it only works. Why use Netty? What are its advantages? None of this is really clear.

This article will say from the historical source.

Traditional IO

Before Netty and NIO, we wrote IO applications using packages provided under Java.io.*.

For example, the following pseudocode:

ServeSocket serverSocket = new ServeSocket(8080);
Socket socket = serverSocket.accept() ;
BufferReader in = .... ;

String request ;
 
while((request = in.readLine()) ! =null) {new Thread(new Task()).start()
}
Copy the code

Such a thread can only handle one connection.

If you have 100 client connections you have to open 100 threads, 1000 you have to open 1000 threads.

Keep in mind that thread resources are precious, and each creation consumes it, and each thread has to allocate stack memory for it.

Even if we gave the JVM enough memory, the context switching caused by a large number of threads was unbearable.

And the traditional IO is blocking mode, each response must be initiated IO request, processing request completion and return at the same time, the direct result is poor performance, low throughput.

Reactor model

Therefore, a high performance IO model commonly used in the industry is Reactor.

It is an asynchronous, non-blocking event-driven model.

It is usually manifested in the following three ways:

Single thread

As can be seen from the figure:

It is a thread that receives the client’s connection and dispatches the request to the corresponding event handler. The whole process is completely asynchronous and non-blocking. And there is no problem sharing resources at all. So in theory the throughput is not bad.

But because it is a thread, the utilization rate of multi-core CPU is not high, once there are a large number of clients connected to the performance is bound to decline, and even a large number of requests can not respond. The worst case scenario is that if the thread fails somewhere and goes into an infinite loop, the entire service becomes unavailable!

multithreading

Hence the multithreaded model.

In fact, the biggest improvement is to change the original event processing to multi-threading.

This can be implemented based on Java’s own thread pool, so the performance implications for handling large numbers of requests are huge.

For all that, there’s still one place that’s theoretically a single point; That’s the thread that handles the client connection.

Because most server applications handle some business, such as authentication, at some point during connection, this thread can still have performance problems as more and more clients are connected.

So we have the following thread model.

Master slave multithreading

In this model, the thread that the client connects to is also changed to multi-thread, called the main thread.

Multiple child threads are also used to handle event responses so that both connections and events are high-performance.

Netty implementation

With all that said, Netty’s threading model is similar.

Let’s go back to the server code from the previous SpringBoot integration of long-connection heartbeat:

    private EventLoopGroup boss = new NioEventLoopGroup();
    private EventLoopGroup work = new NioEventLoopGroup();


    /** * Start Netty **@return
     * @throws InterruptedException
     */
    @PostConstruct
    public void start(a) throws InterruptedException {

        ServerBootstrap bootstrap = new ServerBootstrap()
                .group(boss, work)
                .channel(NioServerSocketChannel.class)
                .localAddress(new InetSocketAddress(nettyPort))
                // Keep the connection long
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childHandler(new HeartbeatInitializer());

        ChannelFuture future = bootstrap.bind().sync();
        if (future.isSuccess()) {
            LOGGER.info("Netty started successfully"); }}Copy the code

The boss is the equivalent of the thread pool that handles client connections in the Reactor model.

Work is the natural thread pool for handling events.

So how to implement the above three modes? It’s actually quite simple:

Single-threaded model:

private EventLoopGroup group = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap()
                .group(group)
                .childHandler(new HeartbeatInitializer());
Copy the code

Multithreaded model:

private EventLoopGroup boss = new NioEventLoopGroup(1);
private EventLoopGroup work = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap()
                .group(boss,work)
                .childHandler(new HeartbeatInitializer());
Copy the code

Master and slave multithreading:

private EventLoopGroup boss = new NioEventLoopGroup();
private EventLoopGroup work = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap()
                .group(boss,work)
                .childHandler(new HeartbeatInitializer());
Copy the code

I believe you will understand.

conclusion

In fact, after reading the Netty thread model can we usually do high performance applications to bring some inspiration?

I think so:

  • The interface is transferred from synchronous to asynchronous processing.
  • Result of callback notification.
  • Multithreading improves concurrency efficiency.

That’s all there is to it, but doing that leads to other problems:

  • How are transactions guaranteed after asynchrony?
  • What happens when a callback fails?
  • Multithreading brings context switching and resource sharing problems.

It’s a game, and it’s trial and error to be as efficient as possible.

The relevant code above:

Github.com/crossoverJi…

Welcome to pay attention to the public account to communicate: