Netty this framework believe everyone is very familiar with, Java world network IO processing of the master, many of the framework we use the underlying communication are Netty implementation, such as Dubbo, Hadoop and so on, but all Java system instant communication system, can not bypass Netty, I also continue to learn, Today, I will take a look at the basic use of Netty, and then I will analyze the various components of Netty in depth. My personal level is limited, if there is incorrect, I hope you can correct me.
Create a Netty server degree using SpringBoot to integrate Netty:
package com.example.nettysourcedemo; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import io.netty.util.concurrent.DefaultThreadFactory; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @Component @Slf4j public class ServerRunner implements CommandLineRunner { @Override public void run(String... Args) throws Exception {/** * NioEventLoopGroup is itself an eventLoopExecutor containing a childGroup=EventExecutor[] * The array is NioEventLoop, and each NioEventLoop contains a selector, as well as an Executor * The executor can be used to perform a task, in the use of executor. When performing the task, the execute will use ThreadPerTaskExecutor. The execute () method performs * This method in turn calls DefaultThreadFactory to create a thread to start the execution of the task * focusing on the parent class constructor */ NioEventLoopGroup boss = new executed in the NioEventLoopGroup constructor NioEventLoopGroup(new DefaultThreadFactory("boss")); NioEventLoopGroup worker = new NioEventLoopGroup(new DefaultThreadFactory("worker")); NioEventLoopGroup business = new NioEventLoopGroup(new DefaultThreadFactory("business")); ServerBootstrap b = new ServerBootstrap(); B. Group (boss,worker) // Call the constructor of ReflectiveChannelFactory, Create NioServerSocketChannel. Channel (NioServerSocketChannel. Class) / / set the boss the thread attribute. The option (ChannelOption SO_BACKLOG, 1024) // Set the worker thread properties, ChildOption (channeloption. TCP_NODELAY,true) //ChannelInitializer is also a ChannelInboundHandler. The main function is to add handlers to the pipeline, ChildHandler (new ChannelInitializer<SocketChannel>() {@override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); // Execute business Handler pipeline. AddLast (Business,"stringDecoder",new stringDecoder ()); pipeline.addLast(business,"stringEncoder",new StringEncoder()); pipeline.addLast(business,"simpleHandler",new SimpleHandler()); pipeline.addLast(business,"realHandler",new RealHandler()); }}); ChannelFuture future = b.bind(9080).sync(); log.info("netty server started"); future.channel().closeFuture().sync(); boss.shutdownGracefully(); worker.shutdownGracefully(); business.shutdownGracefully(); }}Copy the code
The ServerRunner class implements the CommandLineRunner interface, which tells the Spring container that it needs to run the class. Of course, the @Component annotation is also necessary to tell the Spring container that this is a JavaBean and needs to be managed by the container.
A relatively simple Netty server program mainly includes setting parentGroup thread pool (boss), childGroup thread pool (worker), setting the channel type used (NioServerSocketChannel), Set the parentGroup thread properties (#option()), the childGroup thread properties (#childOption()), the pipeline handler (#childHandler()), and the bind port (#bind()).
The program I wrote has one more thread pool for Business than described above, which is mainly used to process time-consuming business processes.
Netty helpfully provides the ServerBootstrap startup class, which can launch a powerful NettyServer with just a few lines of code.
Why have a parentGroup thread pool and a childGroup thread pool? This brings us to Netty’s famous Reactor model, which uses a different model for each thread pool.
-
Only set parentGroup (1)
NioEventLoopGroup boss = new NioEventLoopGroup(1);
-
Set parentGroup only (default)
NioEventLoopGroup boss = new NioEventLoopGroup();
-
Set parentGroup and childGroup
NioEventLoopGroup boss = new NioEventLoopGroup();
NioEventLoopGroup worker = new NioEventLoopGroup();
1. Set only parentGroup and set it to 1Of this model, the entire reactor, only a single thread, the thread as both father and mother, this thread to polling client connection status, and to deal with connection of IO operations, in addition, the IO operations, also want to be in this thread for processing, which may greatly delay the IO request response, it can be said that this thread is very tired. This mode is only suitable for the system with very few connections, such as the Internet, which is prone to tens of millions or even hundreds of millions of concurrent, completely unacceptable.
As shown below, there is only one boss thread when the application starts, and still only one boss thread when multiple clients are connected.2. Set parentGroup and the parameter value is greater than 1(the default value is twice the number of logical cores on the current server.) If parentGroup is set, one thread polls the connection events of the client, and the other threads process I/O events after the connection of the client.ParentGroup is set to the default value when the application starts with only one boss thread.When there is a client connection, there are two boss threads.When there are two clients connected, there are three boss threads.When both parentGroup and childGroup are set to default values, only one boss thread in parentGroup polls for client connection events. When a client is connected, All IO processing is handed over to the threads in the childGroup.When the application starts, there is only one boss threadWhen there is a client connection, there is a boss thread and a worker threadWhen two clients are connected, there is one boss thread and two worker threadsWhen parentGroup and childGroup are both set, parentGroup has only one thread running. However, the server only listens on one port.When there are two clients connected to different ports, there are two bosses and two worker threadsTherefore, the parentGroup thread only listens for connection events on the port, and the IO operations are handled by the childGroup thread.
In each of the above cases, the code needs to be modified as follows when the business thread is not enabled:
pipeline.addLast("stringDecoder",new StringDecoder());
pipeline.addLast("stringEncoder",new StringEncoder());
pipeline.addLast("simpleHandler",new SimpleHandler());
pipeline.addLast("realHandler",new RealHandler());
Copy the code
What happens if the Business thread is enabled? Test the results after restoring the code: In addition to the boss thread, both the worker thread and the Business thread appear. In this case, the parentGroup thread is responsible for listening for connection events on the port, the childGroup thread is responsible for IO operations such as read()/write(), and the business process handler is handed over to the Business thread pool.Last 10 years, the computer industry for C10K catch head (10000) single problem, now C100K 100000 connection (single) have been able to achieve, people are already looking C10M (single must connect), although now distributed architecture, the cluster architecture is already very mature, can be enough to support thousands or even hundreds of millions of number of connections, However, the computer science community is still sparing no effort to increase the number of concurrent connections on a single machine. I believe that whoever can implement C10M the fastest will become a great company surpassing Tencent.
To make a good im product, you need to have a deep understanding of Linux server network, IO, files, etc., in addition to Java side knowledge.
This article mainly introduces the Reactor model differences caused by the configuration of boss and worker threads in NettyServer. The next article introduces the creation process of NioEventLoopGroup (which is quite mind-provoking).