netty series: make TCP connection faster and faster

Posted by cottonbuds2005 on Tue, 08 Feb 2022 18:16:39 +0100

brief introduction

You should be familiar with the classic TCP triple handshake. The triple handshake should be the best solution according to reason. Of course, this is for the general situation. So in some special cases, can you improve the speed of TCP connection establishment?

The answer is yes. That's what we're going to talk about today: TCP fast open and netty.

TCP fast open

What is TCP fast open?

TCP fast open can also be abbreviated as TFO, which is an extension of TCP protocol. Why fast open? This is because TFO can bring some data when initializing and establishing a connection. In this way, after the TCP connection is established, the number of interactions with the server can be reduced, so as to reduce the response time under specific circumstances.

Since TFO is so good, why do we rarely see people using TFO protocol?

This is because TFO is defective, because TFO will bring some data information in the sync package. When the sync package is retransmitted, the receiver will receive duplicate data.

Therefore, if TFO is used, the receiver needs to be able to handle duplicate data.

In the program world, there is a good name for preventing repeated data submission, which is called idempotency. Only servers with idempotency can use TFO.

Turn on TFO

Since TFO is so excellent, how can we start TFO?

The startup of TFO first needs the support of the operating system. If you are a mac system, congratulations. The mac already supports TFO by default. You don't need to do anything.

If you are a Linux system, you need to check / proc/sys/net/ipv4/tcp_fastopen this file.

tcp_fastopen can have four values, as follows:

0 - indicates that TFO is not turned on 1 - indicates that TFO is enabled, but it is only valid for the client 2 - indicates that TFO is enabled, but it is only valid for the server side 3 - indicates that TFO is enabled and is valid for both client and server

Through the above settings, we have enabled TFO support in the operating system layer.

Next, let's look at how to use TFO in netty.

netty support for TFO

First, let's look at how to enable TFO support on the server side of netty.

Before that, let's review how to recommend an ordinary netty server:

EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new TFOServerHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            // Bind ports and start receiving connections
            ChannelFuture f = b.bind(port).sync();

In the above code, we can see that the ServerBootstrap can set the option parameter. The ChannelOption contains all the channel parameters that can be set, and the corresponding TFO parameter is ChannelOption TCP_ Fastopen, so we just need to add it to ServerBootstrap:

sb.option(ChannelOption.TCP_FASTOPEN, 50)

ChannelOption. TCP_ The value of fastopen indicates the number of fast open requests that can be in a waiting state in a socket connection.

For the client, some changes are also needed. First, let's see how the traditional client works:

 EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
             .channel(NioSocketChannel.class)
             .handler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 protected void initChannel(SocketChannel ch) throws Exception {
                     ChannelPipeline p = ch.pipeline();
                     p.addLast(new TFOClientHandler());
                 }
             });

            // Connect server
            ChannelFuture f = b.connect(HOST, PORT).sync();

To support TFO, the client needs to add the following operations:

b.option(ChannelOption.TCP_FASTOPEN_CONNECT, true)

Remember what TFO does? TFO sends some data in the sync package. Therefore, we need to process the sent data on the client side, that is, we need to send messages to the channel before the client and server sides establish a connection.

To obtain a non connected channel, you can call the register method of Bootstrap to obtain the channel:

Channel channel = b.register().sync().channel();

Then write byteBuf to the channel:

ByteBuf fastOpenData = directBuffer();
            fastOpenData.writeBytes("TFO message".getBytes(StandardCharsets.UTF_8));
            channel.write(fastOpenData);

Finally, establish a connection with the server:

// Connect server
            SocketAddress serverAddress =  SocketUtils.socketAddress("127.0.0.1", 8000);
            ChannelFuture f = channel.connect(serverAddress).sync();

summary

In this way, a client and server supporting TFO are completed. Use it.

The example of this article can be referred to: learn-netty4

This article has been included in http://www.flydean.com/44-netty-tcp-fast-open/