Introduction
Netty is a high-performance NIO network framework, which greatly reduces the threshold of network programming and provides a simple and easy-to-use api.
The startup of the client and server is a very simple template code. Our more energy is to write the ChannelHandler for processing business logic. You can write a simple Http server, Im system, etc. by looking at a few demos.
Compared with Java nio native api, Netty has the following advantages
- Provide simple and easy-to-use api, to achieve the same function, you can use java nio and netty to achieve it, you will know how cool netty is to use
- High stability, such as solving the bug of jdk select empty polling
- High scalability, many components can be reused. By default, a handler for handling http, websocket and other protocols is provided, and various codec algorithms are implemented.
How does Reactor support high concurrency?
Netty's ability to support high concurrency is inseparable from its development model Reactor
category | Development model |
---|---|
BIO | Thread-Per-Connection |
NIO | Reactor |
AIO | Proactor |
Use example categories
BIO: queuing for
dinner NIO: ordering and waiting to be called
Thread-Per-Connection
The development model of Thread-Per-Connection should be clear to many people. As the name implies, one request to create a thread cannot support high concurrency. Of course, you can use the thread pool to avoid the repeated creation of threads.
Reactor
The core process of Reactor is
- Register for events of interest
- Scan for events of interest
- Deal with the incident accordingly
The evolution of the Reactor model is as follows
Single Reactor single thread
Implementation process
- The Reactor object monitors client request events through select, and distributes them through dispatch after receiving the event
- If it is a connection establishment event, hand it over to Acceptor to process the connection request through accept, and then create a handler object to handle the subsequent business processing after the connection is completed
- If it is a read-write event, call the corresponding handler to process the request. The handler will complete the entire complete business process of read->business processing->send
advantage
The model is simple, the whole process is completed in one thread
Disadvantage
-
The performance problem is that there is only one thread and cannot play the performance of a multi-core CPU. And when the handler is processing the request, it cannot handle the connection request, which easily leads to a performance bottleneck
-
Reliability issues, threads are terminated unexpectedly or infinite loops, the system cannot receive and process external messages, causing node failures
Single Reactor multi-threaded
Implementation process
- The Reactor object monitors client request events through select, and distributes them through dispatch after receiving the event
- If it is a connection establishment event, hand it over to Acceptor to process the connection request through accept, and then create a handler object to handle the subsequent business processing after the connection is completed
- If it is a read-write event, call the corresponding handler to process the request
- The handler is only responsible for reading and responding to events, and does not do specific business processing. After reading the data, it will be distributed to a thread in the Worker thread pool to process the business, and the result will be returned to the handler after processing.
- The handler returns to the client after receiving the response
advantage
Make full use of the processing power of multi-core cpu
Disadvantage
Reactor runs in a single thread and handles the monitoring and response of all events, which is prone to performance bottlenecks in high concurrency scenarios
Master-slave Reactor multithreading
Reactor is prone to bottlenecks under high concurrency, so Reactor is divided into two parts, MainReactor only handles connection events, SubReactor only handles read and write events
If it is a connection event, MainReactor is directly handed over to Acceptor for processing, if it is a read-write event, MainReactor is handed over to SubReactor for processing
When we are writing a Netty program, two EventLoopGroups will be created, one is bossGroup and the other is workerGroup. bossGroup is used to handle connection requests, and workerGroup is used to handle read and write requests
EventLoop corresponds to Reactor in Reactor mode, EventLoopGroup is a collection of EventLoop
MainReactor has one, which runs in a single thread. There are multiple SubReactors, running in multiple threads
I recommend you to take a look at Doug Lea's article explaining the Reactor mode (the concurrency package you use is written by him) to ensure that you can have a deeper impression
http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf
Now our commonly used NIO framework is Netty. It is very convenient to switch these three modes in Netty. The code is as follows
Of course Netty has made certain improvements. That is, there can be multiple Reactor threads in single Reactor multithreading and master-slave Reactor multithreading
// 单Reactor单线程
EventLoopGroup eventLoopGroup = new NioEventLoopGroup(1);
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(eventLoopGroup);
// 单Reactor多线程
// EventLoopGroup不指定线程数的话默认是cpu核数的2倍
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(eventLoopGroup);
// 主从Reactor多线程
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup);