Netty Learning (7): Heartbeat Detection Mechanism

1. What is the heartbeat detection mechanism

The so-called heartbeat is a special data packet sent periodically between the client and the server in the TCP long connection to inform the other party that it is still online to ensure the validity of the TCP connection.

The heartbeat mechanism is mainly that when the client and the server are connected for a long time, the client needs to send heartbeat packets regularly to ensure that it is alive, otherwise a connection that does not work for a long time will waste the resources of the server.

2. Applicable scenarios of the heartbeat detection mechanism

The application scenarios of persistent connection are very extensive, such as monitoring system, IM system, real-time quotation system, push service and so on. Scenarios like these pay more attention to real-time performance. If DNS resolution is required every time data is sent, the process of establishing a connection will definitely greatly affect the experience.

The maintenance of long connections will inevitably require a set of mechanisms to control. For example, HTTP/1.0 adds the Connection:Keep-Alive parameter in the header. If the current request needs to be kept alive, add this parameter as an identifier. Otherwise, the server will not keep the state of the connection and close the connection after sending the data. Keep-Alive is enabled by default after HTTP/1.1.

Netty is developed based on the TCP protocol. In the implementation of the four-layer protocol TCP protocol, a keepalive message is also provided to detect whether the peer is available. The TCP layer will send the corresponding KeepAlive probe to determine the availability of the connection after the timer expires.

Therefore, heartbeat detection generally exists in scenarios where a long connection is established or a keep-alive is required.

3. Netty's heartbeat detection mechanism

The basic protocol is not so perfect for the application. A Netty server may face tens of thousands of connections. How to maintain these connections is what the application should handle. The IdleStateHandler class is provided in Netty specifically for handling heartbeats.

The constructor of IdleStateHandler is as follows:

CopypublicIdleStateHandler(long readerIdleTime, long writerIdleTime, 
                            long allIdleTime,TimeUnit unit){  
}

illustrate:

  1. IdleStateHandler is a processor provided by netty to handle idle state

  1. long readerIdleTime : Indicates how long it has not been read, it will send a heartbeat detection packet to check whether it is connected

  1. long writerIdleTime : Indicates how long it has not been written, it will send a heartbeat detection packet to check whether it is connected

  1. long allIdleTime : Indicates how long there is no reading or writing, and a heartbeat detection packet will be sent to detect whether it is connected

The documentation for IdleStateHandler states:

triggers an {@link IdleStateEvent} when a {@link Channel} has not performed
read, write, or both operation for a while.

4. Example of Netty heartbeat detection mechanism

I use an example I will write to explain what is the heartbeat detection mechanism. I'm going to implement something like this:

  1. When the server has not read for more than 3 seconds, it will prompt to read idle

  1. When the server has no write operation for more than 5 seconds, it will prompt to write idle

  1. When the server has no read or write operations for more than 7 seconds, it prompts that the read and write is idle

Server:

public class MyServer {
    public static void main(String[] args) throws Exception{


        //创建两个线程组
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(); //8个NioEventLoop
        try {

            ServerBootstrap serverBootstrap = new ServerBootstrap();

            serverBootstrap.group(bossGroup, workerGroup);
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.handler(new LoggingHandler(LogLevel.INFO));
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    //加入一个netty 提供 IdleStateHandler
                    /*
                     *当 IdleStateEvent 触发后 , 就会传递给管道 的下一个handler去处理
                     *通过调用(触发)下一个handler 的 userEventTiggered , 在该方法中去处理 IdleStateEvent(读空闲,写空闲,读写空闲)
                     */
                    pipeline.addLast(new IdleStateHandler(7000,7000,10, TimeUnit.SECONDS));
                    //加入一个对空闲检测进一步处理的handler(自定义)
                    pipeline.addLast(new MyServerHandler());
                }
            });

            //启动服务器
            ChannelFuture channelFuture = serverBootstrap.bind(7000).sync();
            channelFuture.channel().closeFuture().sync();

        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

Custom handler (determine how to deal with it in the handler):

public class MyServerHandler extends ChannelInboundHandlerAdapter {

    /**
     *
     * @param ctx 上下文
     * @param evt 事件
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {

        if(evt instanceof IdleStateEvent) {

            //将  evt 向下转型 IdleStateEvent
            IdleStateEvent event = (IdleStateEvent) evt;
            String eventType = null;
            switch (event.state()) {
                case READER_IDLE:
                  eventType = "读空闲";
                  break;
                case WRITER_IDLE:
                    eventType = "写空闲";
                    break;
                case ALL_IDLE:
                    eventType = "读写空闲";
                    break;
            }
            //这里已经可以知道浏览器所处的空闲是何种空闲,可以执行对应的处理逻辑了
            System.out.println(ctx.channel().remoteAddress() + "--超时时间--" + eventType);
            System.out.println("服务器做相应处理..");

            //如果发生空闲,我们关闭通道
           // ctx.channel().close();
        }
    }
}

Guess you like

Origin blog.csdn.net/m0_49499183/article/details/129492785