What is Netty? Why use Netty? What are the components of Netty?

What is Netty

1. Netty is a client server framework based on NIO, which can be used to develop network applications quickly and easily.
2. It greatly simplifies and optimizes network programming such as TCP and UDP socket server, and has even better performance and security.
3. Support a variety of protocols, such as FTP, SMTP, HTTP and various binary and text-based traditional protocols.
The official conclusion is that Netty has successfully found a way to achieve ease of development, performance, stability and flexibility without compromising maintainability and performance.

In addition to the above, many open source projects, such as Dubbo, RocketMQ, Elasticsearch, gRPC and so on, use Netty.

Why use Netty

  1. It is easier to use than directly using the NIO related API of JDK.
  2. The unified API supports multiple transmission types, blocking and non blocking.
  3. Simple and powerful threading model.
  4. The built-in codec solves the problem of TCP packet sticking / unpacking.
  5. With various protocol stacks.
  6. True connectionless packet socket support.
  7. It has higher throughput, lower latency, lower resource consumption and less memory replication than using the Java core API directly.
  8. Good security, complete SSL/TLS and StartTLS support.
  9. The community is active, mature and stable. It has experienced the use and test of large projects, and many open source projects use Netty, such as Dubbo, RocketMQ and so on.

Application scenario

  1. What NIO can do, netty can do better. Netty is mainly used for network communication:
  2. As a network communication tool of RPC framework: in our distributed system, different service nodes often need to call each other. At this time, RPC framework is needed. How to communicate between different service nodes? You can use Netty to do this. For example, if I call a method of another node, at least let the other party know which method in which class and related parameters I call!
  3. Implement our own HTTP server: we can implement a simple HTTP server through Netty, which should be familiar to us. When it comes to HTTP server, as a Java back-end development, we generally use Tomcat more. A basic HTTP server can handle common HTTP Method requests, such as POST requests, GET requests, and so on.
  4. Implement an instant messaging system: using Netty, we can implement an instant messaging system that can chat similar to wechat,
  5. Implementation of message push system: there are many message push systems on the market based on Netty.

Netty's high performance

  • Heartbeat, to the server: idle sessions will be cleared periodically. inactive(netty5), * * to the client: * * used to detect whether the session is disconnected and restarted, and to detect network delay. The idleStateHandler class is used to detect the session state
  • **Serial lock free design, * * that is, the processing of messages should be completed in the same thread as far as possible without thread switching, so as to avoid multi-threaded competition and synchronous lock. On the surface, the serial design seems to have low CPU utilization and insufficient concurrency. Compared with the serial thread pool design, the performance of multiple threads running in parallel without lock can be adjusted. However, compared with the serial thread pool design, the performance of multiple threads running in parallel without lock can be better.
  • Reliability and Link validity detection: link idle detection mechanism, read / write idle timeout mechanism; Memory protection mechanism: reuse bytebuf through memory pool; Decoding protection of bytebuf; Graceful shutdown: no longer receiving new messages, pre-processing operations before exiting, and resource release operations.
  • Netty security: supported security protocols: SSL V2 and V3, TLS, SSL one-way authentication, two-way authentication and third-party CA authentication.
  • The embodiment of efficient concurrent programming: the massive and correct use of volatile; CAS and atomic class are widely used; Use of thread safe container; Improve concurrency performance through read-write locks. Three principles of IO communication performance: transmission (AIO), protocol (Http) and thread (master-slave multithreading)
  • Function of traffic integer (transformer): prevent downstream network elements from being crushed and business flow interrupted due to uneven performance of upstream and downstream network elements; Prevent the communication module from receiving messages too fast and the back-end business thread is not processed in time, resulting in dead support

Netty core components

Bootstrap and ServerBootstrap

When you need to connect the client or bind the server to the specified port, you need to use Bootstrap. There are two types of ServerBootstrap: one is for the client and the other is for the server. No matter what protocol the program uses, whether it is creating a client or server, it needs to use "boot".

Bootstrap is the boot class / auxiliary class of the client

EventLoopGroup group = new NioEventLoopGroup(); 
try { 
	//To create a client boot / helper class:
	Bootstrap Bootstrap b = new Bootstrap(); 
	//Specify thread model 
	b.group(group). ...... 
	// Attempt to establish connection 
	ChannelFuture f = b.connect(host, port).sync(); 
	f.channel().closeFuture().sync(); 
} finally { 
	// Gracefully close related thread group resources 
	group.shutdownGracefully(); 
}

Boot class / auxiliary class of ServerBootstrap client

// 1.bossGroup is used to receive connections and workerGroup is used for specific processing 
EventLoopGroup bossGroup = new NioEventLoopGroup(1); 
EventLoopGroup workerGroup = new NioEventLoopGroup(); 
try { 
	//2. Create a server startup boot / auxiliary class:
	ServerBootstrap ServerBootstrap b = new ServerBootstrap(); 
	//3. Configure two thread groups for the boot class and determine the thread model 
	b.group(bossGroup, workerGroup). ...... 
	// 6. Binding port 
	ChannelFuture f = b.bind(port).sync(); 
	// Wait for the connection to close 
	f.channel().closeFuture().sync(); 
} finally { 
	//7. Gracefully close the related thread group resources 
	bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); 
} 

Bootstrap usually uses the connect () method to connect to the remote host and port as a client in Netty TCP protocol communication. In addition, bootstrap can also bind a local port through the bind() method as one end of UDP protocol communication.
ServerBootstrap usually uses the bind() method to bind to the local port and wait for the client to connect.

Bootstrap only needs to configure one thread group - EventLoopGroup, while ServerBootstrap needs to configure two thread groups - EventLoopGroup, one for receiving connections and the other for specific processing.

classificationBootstrapServerBootstrap
Network functionConnect to remote hosts and portsBind local port
Number of eventloopgroups12

A ServerBootstrap can be considered to have two Channel sets,

The first set contains a singleton ServerChannel, which represents holding a socket bound with a local port;

The second set contains all channels created to handle incoming connections from clients received by the server.

EventLoop and EventLoopGroup

EventLoop defines the core abstraction of Netty, which is used to handle the events that occur in the life cycle of the connection.

The main function of EventLoop is actually to listen to network events and call the event processor to process relevant I/O operations.

What is the direct connection between Channel and EventLoop?

Channel is an abstract class of Netty network operations (read and write operations). EventLoop is responsible for processing the I/O operations of the channel registered on it. The two cooperate to participate in I/O operations.

EventLoopGroup contains multiple eventloops, each of which usually contains a Thread. EventLoop processes IO events on its own Thread to ensure Thread safety

When NioEventLoopGroup does not specify the number of threads, the default is the current number of cpu threads * 2

  1. EventLoopGroup is an abstraction of a group of eventloops. In order to make better use of multi-core CPU resources, Netty generally has multiple eventloops working at the same time, and each EventLoop maintains a Selector instance.
  2. EventLoopGroup provides the next interface. You can get one of the eventloops from the group according to certain rules to process tasks. In Netty server-side programming, we generally need to provide two eventloopgroups, such as BossEventLoopGroup and WorkerEventLoopGroup.
  3. Usually, a service port, that is, a ServerSocketChannel, corresponds to a Selector and an EventLoop thread. BossEventLoop is responsible for receiving the connection from the client and handing the SocketChannel to the WorkerEventLoopGroup for IO processing

  • BossEventLoopGroup is usually a single threaded EventLoop. EventLoop maintains a Selector instance registered with ServerSocketChannel. BossEventLoop constantly polls the Selector to separate connection events
  • Usually OP_ACCEPT event, and then give the received SocketChannel to the WorkerEventLoopGroup
  • WorkerEventLoopGroup will select one of the eventloops by next to register the SocketChannel with its maintained Selector and handle its subsequent IO events

EventLoop inheritance diagram

Channel

Channel interface is an abstract class of Netty for network operations. It includes basic I/O operations, such as bind(), connect(), read(), write().

The commonly used Channel interface implementation classes are NioServerSocketChannel (server) and NioSocketChannel (client). These two channels can correspond to the two concepts of ServerSocket and Socket in BIO programming model. The API provided by Netty's Channel interface greatly reduces the complexity of using Socket class directly.

Channel channel = ...; // Get the reference of channel
ByteBuf buf = Unpooled.copiedBuffer("your data", CharsetUtil.UTF_8); //1 ChannelFuture cf = channel.writeAndFlush(buf); //2
cf.addListener(new ChannelFutureListener() { //3
@Override
public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) { //4
} });
  1. Create ByteBuf to save written data
  2. Write data and refresh
  3. Add ChannelFutureListener to receive the notification after the write operation is completed
  4. The write operation completed without error
  5. An error occurred when the write operation completed

channel declaration cycle

statedescribe
ChannelUnregisteredThe Channel has been created but has not been registered with EventLoop
ChannelRegisteredChannel has been registered to EventLoop
ChannelActiveThe Channel is active (the remote node that is already connected to it). It can now receive and send data
ChannelInactiveThe Channel is not connected to the remote node

selector

effect:

  • I/O readiness and selection
  • It is the basis of NIO network programming

SelectonKey status

  • OP_ The accept operation set is used to accept the operation of the socket.
  • OP_CONNECT the operation set bit used for socket connection operation.
  • OP_ Operation bit of read operation.
  • OP_WRITE operation bit of write operation.

ChannelHandler

ChannelHandler is a message processor, which is responsible for reading and writing operations and client connection.

  1. ChannelHandler is an interface that handles I/O events or intercepts I/O operations and forwards them to its
    The next handler in the channelpipeline.
  2. ChannelHandler itself does not provide many methods, because there are many methods to be implemented in this interface
    You can inherit its subclasses during its use
  3. Subclass > > netty's own ChannelHandler

ChannelPipeline provides a container for the chain of ChannelHandler and defines an API for propagating inbound and outbound event flows along the chain. When a Channel is created, it will be automatically assigned to its exclusive ChannelPipeline.

You can add one or more channelhandlers on the ChannelPipeline through the addLast() method, because a data or event may be processed by multiple handlers. When a ChannelHandler has finished processing, it will hand over the data to the next ChannelHandler.

Netty can send messages in two ways. You can write messages directly to the Channel or write ChannelHandlerContext objects. The main difference is that the former method will cause the message to start from the tail of the ChannelPipeline, while the latter will cause the message to start from the next processor of the ChannelPipeline.

Sub interface of ChannelHandler:

  • ChannelInboundHandler -- process inbound data and various state changes;
  • ChannelOutboundHandler -- handles outbound data and allows interception of all operations;
  • Channelduplex handler -- can handle both inbound and outbound data.
  1. SslChannel: it is responsible for encrypting and decrypting requests. It is the first ChannelHandler placed on the ChannelPipeline

  1. HttpClientCodec and HttpServerCodec: HttpClientCodec is responsible for decoding the request bytecode into HttpRequest, HttpContent and LastHttpContent messages, and converting the corresponding into bytes; HttpServerCodec is responsible for parsing the bytecode into HttpResponse, HttpContent and LastHttpContent messages at the server, and converting it into bytes accordingly.

    HttpServerCodec combines HttpResponseEncoder and HttpRequestDecoder
    Httprequesteencoder and HttpResponseDecoder are combined in HttpClientCodec

  2. HttpObjectAggregate: responsible for aggregating http into complete messages rather than original parts.

  3. HttpContentCompressor and HttpContentDecompressor: HttpContentCompressor is used to compress data on the server and HttpContentDecompressor is used to decompress data on the client

  4. IdleStateHandler: the IdleStateEvent event is triggered when the connection is idle for too long

  5. ReadTimeoutHandler: if no inbound data is received within the specified time, throw ReadTimeoutException and close the Channel.

  6. WriteTimeoutHandler: if no outbound data write is received within the specified time, throw WriteTimeoutException and close the Channel.

  7. DelimiterBasedFrameDecoder: a general decoder that uses any user supplied delimiter to extract frames.

  8. FixedLengthFrameDecoder: extract the fixed length frame when calling the constructor.

  9. Chuck edwriterhandler: copy large files from file system to memory [DefaultFileRegion for large file transfer]

be careful:

ChannelHandler instances with @ Sharable annotation can be added to multiple channelpipelines. That is, a single ChannelHandler instance can have multiple channelhandlercontexts, so you can call different channelhandlercontexts to get the same ChannelHandler. If a ChannelHandler instance without @ Sharable annotation is added to multiple channelpipelines, an exception will be thrown; The ChannelHandler annotated with @ Sharable must be used safely on different threads and channels. ChannelHandler instances with @ Sharable annotation can be added to multiple channelpipelines. That is, a single ChannelHandler instance can have multiple channelhandlercontexts, so you can call different channelhandlercontexts to get the same ChannelHandler. If a ChannelHandler instance without @ Sharable annotation is added to multiple channelpipelines, an exception will be thrown; The ChannelHandler annotated with @ Sharable must be used safely on different threads and channels.

Outbound ChannelOutboundHandler interface

Outbound operations and data will be processed by ChannelOutboundHandler. Its methods will be called by Channel, ChannelPipeline and ChannelHandlerContext. A powerful feature of ChannelOutboundHandler is that it can postpone operations or events on demand, which makes it possible to process requests in some complex ways. For example, if a write to a remote node is paused, you can delay the flush operation and continue later.

public interface ChannelOutboundHandler extends ChannelHandler {

/**

When the request will Channel Called when binding to local address

/

void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception;

/**

When the request will Channel Called when connecting to a remote node

/

void connect(

ChannelHandlerContext ctx, SocketAddress remoteAddress,

SocketAddress localAddress, ChannelPromise promise) throws Exception;

/**

When the request will Channel Called when disconnected from a remote node

/

void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;

/**

When requested to close Channel Called when

/

void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;

/**

When the request will Channel From its EventLoop Called on logoff

/

void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;

/**

When request from Channel Called when more data is read

/

void read(ChannelHandlerContext ctx) throws Exception;

/**

When the request passes Channel Called when writing data to a remote node

/

void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception;

/**

When the request passes Channel Called when the queued data is flushed to the remote node

/

void flush(ChannelHandlerContext ctx) throws Exception;

}

Inbound ChannelInboundHandler interface

/**

{@link ChannelHandler} which adds callbacks for state changes. This allows the user

to hook in to state changes easily.

/

public interface ChannelInboundHandler extends ChannelHandler {

/**

When Channel Already registered to its EventLoop And can handle I/O Called when

/

void channelRegistered(ChannelHandlerContext ctx) throws Exception;

/**

When Channel From its EventLoop Sign out and cannot process any I/O Called when

/

void channelUnregistered(ChannelHandlerContext ctx) throws Exception;

/**

When Channel Called when active; Channel Already connected/Bound and ready

/

void channelActive(ChannelHandlerContext ctx) throws Exception;

/**

When Channel Called when it leaves the active state and no longer connects to its remote node

/

void channelInactive(ChannelHandlerContext ctx) throws Exception;

/**

When from Channel Called while reading data

/

void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;

/**

When Channel Called when a read operation on is completed

/

void channelReadComplete(ChannelHandlerContext ctx) throws Exception;

/**

When ChannelnboundHandler.fireUserEventTriggered()Method is called because a POJO Was preached ChannelPipeline

/

void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;

/**

When Channel Called when the writable state of changes. The user can ensure that the write operation does not complete too fast (to avoid occurrence) OutOfMemoryError)Or you can Channel Resume writing when it becomes writable again. You can call Channel of isWritable()Method to detect Channel Writability of. Thresholds related to Writeability can be passed Channel.config().setWriteHighWaterMark()and Channel.config().setWriteLowWater-Mark()Method to set

/

void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception;

/**

Called if an exception object that can be thrown is thrown.

/

@Override

@SuppressWarnings("deprecation")

void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;

}

ChannelPipeline

  1. ChannelPipeline is a collection of handlers, which is responsible for processing and intercepting inbound or outbound data
    outbound events and operations are equivalent to a chain running through Netty. (it can also be understood as follows:
    Channel pipeline is a List that saves ChannelHandler and is used to process or intercept inbound channels
    Events and outbound operations)
  2. ChannelPipeline implements an advanced form of interception filter mode, so that users can fully control things
    How to handle the pieces and how the channelhandlers in the Channel interact with each other
  3. In Netty, each Channel has and only one ChannelPipeline corresponds to it

A channel corresponds to a pipeline, and a pipeline corresponds to n channelhandlers

  • A Channel contains a ChannelPipeline, which maintains a two-way linked list composed of ChannelHandlerContext, and each ChannelHandlerContext is associated with a ChannelHandler
  • Inbound events and outbound events are in a two-way linked list. Inbound events will be passed from the head of the linked list to the last inbound handler, and outbound events will be passed from the tail of the linked list to the first outbound handler. The two types of handlers do not interfere with each other

ChannelPipeline scheduling handler

  1. Context wraps the handler. Multiple contexts form a two-way linked list in the pipeline. The inbound direction is called inbound, starting from the head node, and the outbound method is called outbound, starting from the tail node.
  2. The transfer between nodes is through the fire series methods inside the AbstractChannelHandlerContext class to find the next node of the current node and continue to circulate. It is a filter to complete the scheduling of the handler

ChannelHandlerContext

  1. Save all context information related to the Channel and associate a ChannelHandler object at the same time
  2. That is, the ChannelHandlerContext contains a specific event handler,
    At the same time, the corresponding pipeline and Channel information are also bound in the ChannelHandlerContext, which is convenient to call the ChannelHandler

ChannelHandlerContext represents the association between ChannelHandler and ChannelPipeline. Whenever a ChannelHandler is added to ChannelPipeline, ChannelHandlerContext will be created. The main function of ChannelHandlerContext is to manage the interaction between its associated ChannelHandler and other channelhandlers in the same ChannelPipeline.

ChannelHandlerContext has many methods, some of which also exist in Channel and ChannelPipeline itself, but there is an important difference. If these methods on Channel or ChannelPipeline are called, they will propagate along the whole ChannelPipeline. Calling the same method on the ChannelHandlerContext will start with the currently associated ChannelHandler and will only be propagated to the next ChannelHandler in the ChannelPipeline that can handle the event.

public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {
    /**
     * This instance is bound to the Channel
     */
    Channel channel();

    /**
     * Returns the EventExecutor of the scheduled event
     */
    EventExecutor executor();

    /**
     * Returns the unique name of this instance
     */
    String name();

    /**
     * Returns the ChannelHandler bound to this instance
     */
    ChannelHandler handler();

    /**
     * Returns true if the associated ChannelHandler has been removed from the ChannelPipeline
     */
    boolean isRemoved();

    /**
     * Trigger a call to the fireChannelRegistered() method on the next ChannelInboundHandler
     */
    @Override
    ChannelHandlerContext fireChannelRegistered();

    /**
     * Triggers a call to the fireChannelUnregistered() method on the next ChannelInboundHandler
     */
    @Override
    ChannelHandlerContext fireChannelUnregistered();

    /**
     * Trigger a call to the fireChannelActive() method on the next ChannelInboundHandler
     */
    @Override
    ChannelHandlerContext fireChannelActive();

    /**
     * Triggers a call to the fireChannelInactive() method on the next ChannelInboundHandler
     */
    @Override
    ChannelHandlerContext fireChannelInactive();

    /**
     * Triggers a call to the fireexceptionguess() method on the next ChannelInboundHandler
     */
    @Override
    ChannelHandlerContext fireExceptionCaught(Throwable cause);

    /**
     * Triggers a call to the fireUserEventTriggered() method on the next ChannelInboundHandler
     */
    @Override
    ChannelHandlerContext fireUserEventTriggered(Object evt);

    /**
     * Triggers a call to the fireChannelRead() method on the next ChannelInboundHandler
     */
    @Override
    ChannelHandlerContext fireChannelRead(Object msg);

    /**
     * Triggers a call to the fireChannelReadComplete() method on the next ChannelInboundHandler
     */
    @Override
    ChannelHandlerContext fireChannelReadComplete();

    /**
     * Triggers a call to the firechannelwriteabilitychanged() method on the next ChannelInboundHandler
     */
    @Override
    ChannelHandlerContext fireChannelWritabilityChanged();

    /**
     * Read the data from the Channel to the first inbound buffer; If the reading is successful, a channelRead event will be triggered and the channelReadComplete(ChannelHandlerContext) method of ChannelInboundHandler will be notified (after the last message is read)
     */
    @Override
    ChannelHandlerContext read();

    /**
     * Refresh all pending messages.
     */
    @Override
    ChannelHandlerContext flush();

    /**
     * Returns the ChannelPipeline associated with this instance
     */
    ChannelPipeline pipeline();

    /**
     * Returns the bytebufalocator configured by the Channel associated with this instance
     */
    ByteBufAllocator alloc();

    /******************Supplement*************************/

//write writes the message through this instance and passes through the ChannelPipeline

//writeAndFlush writes and flushes messages through this instance and passes through ChannelPipeline

}


Causes of JVM memory leaks and memory overflows
Explanation and use of common monitoring tools for JVM
Redis common interview questions (I)
MaterializeMySQL engine of ClickHouse (10)
Implementation and difference of three distributed locks
Understanding and use of thread pool

Extra! Extra!

Recently, I interviewed BAT and sorted out an interview material, covering Java core technology, JVM, Java concurrency, SSM, microservice, database, data structure, etc. Want to get it? If you want to improve yourself and want to make progress with excellent people, interested friends can scan the code below the official account. The information is lying in the official account.

  • Collect if you like
  • Like it when you agree
  • Focus on support
  • Comment on questions

One button four times, and your offer four times

--------------------------------

Author: Java technology debt
Original link: https://www.cuizb.top/myblog/article/1645111323
Copyright notice: unless otherwise stated, all articles on this blog are licensed under CC BY 3.0 CN agreement. For reprint, please sign the author and indicate the source of the article.

Keywords: Java Netty

Added by HektoR on Thu, 17 Feb 2022 18:07:57 +0200