Netty parameter tuning

Posted by PCSpectra on Thu, 10 Feb 2022 17:38:30 +0100

1, CONNECT_TIMEOUT_MILLIS

  • Parameters belonging to socketchannel
  • When the client establishes a connection, if the connection cannot be made within the specified milliseconds, a timeout exception will be thrown
  • Note: don't use so in Netty_ Timeout is mainly used for blocking IO, while Netty is non blocking io

Examples

public class TimeOutTest {
    public static void main(String[] args) {
        NioEventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap()
                    .group(group)
                    .channel(NioSocketChannel.class)
                    // Throw an exception if no connection is established within one second
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
                    .handler(new LoggingHandler());
            ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress("localhost", 8080)).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }


    }
}
  • Client through bootstrap The option function is used to configure parameters. The configuration parameters act on SocketChannel
  • The server configures parameters through ServerBootstrap, but different methods need to be selected for different channels
    • Configure parameters on ServerSocketChannel through option
    • Configure the parameters on SocketChannel through childOption

Source code analysis

The thread connecting to the server in the client is the NIO thread, and the main thread throws an exception. How does this achieve timeout judgment and thread communication?

Exception set in connect method of AbstractNioChannel:

    @Override
    public final void connect(
            final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {

            . . .

                // Get timeout from parameter
                int connectTimeoutMillis = config().getConnectTimeoutMillis();
                if (connectTimeoutMillis > 0) {
                    // Execute a scheduled task through schedule
                    connectTimeoutFuture = eventLoop().schedule(new Runnable() {
                        @Override
                        public void run() {
                            ChannelPromise connectPromise = AbstractNioChannel.this.connectPromise;
                            ConnectTimeoutException cause =
                                    new ConnectTimeoutException("connection timed out: " + remoteAddress);
                            //If no connection is obtained after the timeout, tryFailure puts the exception into promise for the main thread to get
                            if (connectPromise != null && connectPromise.tryFailure(cause)) {
                                close(voidPromise());
                            }
                        }
                    }, connectTimeoutMillis, TimeUnit.MILLISECONDS);
                }
                
            . . .
            
            }
        } catch (Throwable t) {
            promise.tryFailure(annotateConnectException(t, remoteAddress));
            closeIfClosed();
        }
    }

The timeout judgment is mainly realized through the schedule method of Eventloop and Promise

  • schedule sets a scheduled task, and executes this method after delaying connectTimeoutMillis seconds
  • If no connection is established within the specified time, the task will be executed, the ConnectTimeoutException exception will be created, and the exception will be passed to the main thread through poise and thrown

2, SO_BACKLOG

This parameter is a parameter of ServerSocketChannel

Triple handshake and connection queue

  • At the first handshake, because the connection between the client and the server has not been fully established, the connection will be put into the semi connection queue
  • After three handshakes, the connection will be put into the full connection queue
  • The server handles the Accept event after three TCP handshakes, that is, after the connection is established. The server gets the connection from the full connection queue and processes it

Before linux 2.2, the backlog size includes the size of two queues. After linux 2.2, the following two parameters are used to control the backlog size

  • Semi connected queue - sync queue
    • Size via / proc / sys / net / IPv4 / TCP_ max_ syn_ The backlog specifies that when syncookies are enabled, there is no logical maximum limit, and this setting will be ignored
  • Full connection queue - accept queue
    • Its size is specified by / proc/sys/net/core/somaxconn. When using the listen function, the kernel will take the smaller value of the two according to the passed backlog parameters and system parameters
    • If the accpet queue is full, the server will send a connection rejection error message to the client

Examples

In Netty, SO_BACKLOG is mainly used to set the size of the full connection queue. When the rate of processing Accept is less than the rate of connection establishment, the number of connections stacked in the full connection queue is greater than so_ If the value set by backlog is, an exception will be thrown

public class BackLogTest {
    public static void main(String[] args) {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap server = new ServerBootstrap()
                    .group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    //Set the full connection queue size to 2
                    .option(ChannelOption.SO_BACKLOG, 2)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {

                        }
                    });

            ChannelFuture channelFuture = server.bind(8080).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

3, TCP_NODELAY

  • Belongs to socketchannel parameter
  • Because of Nagle algorithm, data packets will be piled up to a certain number and sent together, which may lead to a certain delay in data transmission
  • This parameter defaults to false. If the undesired sending is delayed, you need to set this value to true

4, So_ SNDBUF & SO_ RCVBUF

  • SO_SNDBUF belongs to socketchannel parameter (send buffer size)
  • SO_RCVBUF can be used for both socketchannel parameter and serversocketchannel parameter (it is recommended to set it on serversocketchannel) (accept buffer size)
  • This parameter is used to specify the sliding window size of receiver and sender

5, ALLOCATOR

  • Belongs to socketchannel parameter
  • Used to configure whether ByteBuf is pooled or non pooled, direct memory or heap memory

use

ServerBootstrap server = new ServerBootstrap()
                    .childOption(ChannelOption.ALLOCATOR, new PooledByteBufAllocator())
  • Pool and use direct memory
// true indicates that direct memory is used
new PooledByteBufAllocator(true);
  • Pool and use heap memory
// false indicates that heap memory is used
new PooledByteBufAllocator(false);
  • Non pooling and using direct memory
// ture means using direct memory
new UnpooledByteBufAllocator(true);
  • Non pooling and using heap memory
// false indicates that heap memory is used
new UnpooledByteBufAllocator(false);

6, RCVBUF_ALLOCATOR

  • Belongs to socketchannel parameter
  • Control the size of Netty receive buffer
  • It is responsible for the allocation of inbound data, determines the size of inbound buffer (and can be dynamically adjusted), and uniformly adopts direct direct memory. The specific pooling or non pooling is determined by the allocator

Topics: Java Linux Netty Multithreading