How to use Netty to realize remote call in SpringBoot?

Posted by Gruessle on Mon, 31 Jan 2022 21:20:01 +0100

preface

As we all know, establishing socket connection is a very performance consuming thing when we make network connection. Especially in the case of distributed, using thread pool to maintain multiple client connections is a very thread consuming behavior. We have to solve one of the above problems through Netty's network connection technology

Netty

Netty is a NIO client server framework:

  • It can quickly and easily develop network applications, such as protocol servers and clients.

  • It greatly simplifies and simplifies network programming, such as TCP and UDP socket servers.

NIO is a non blocking IO, which has the following characteristics

  • A single thread can connect multiple clients.

  • The selector can manage multiple channels in a single thread, and all new channels must be registered with the selector.

  • A SelectionKey key represents the registration relationship between a specific channel object and a specific selector object.

  • The select() operation of the selector may cause blocking, but the blocking time can be set, and the selector can be awakened with wakeup(), so NIO is non blocking IO.

Netty model selector pattern

Compared with ordinary NIO, it has improved its performance by adopting:

  • NIO adopts multithreading and can use multiple selector s at the same time

  • By binding multiple ports, a selector can register multiple serversocketservers at the same time

  • There can only be one selector in a single thread to realize Channel matching and reuse

Semi package problem

TCP/IP may unpack when sending messages, which makes the receiver unable to know when the received data is a complete data. In traditional BIO, blocking occurs when data cannot be read, but NIO does not. In order to solve the half package problem of NIO, Netty proposed reactor mode on the basis of Selector model, so as to solve the problem that the client request is incomplete on the server.

netty model reactor mode

  • The semi package problem is solved on the basis of selector.

In the above figure, it can be simply described as "boss takes over and let work do": manReactor is used to receive requests (handshake verification with the client), while subReactor is used to process requests (not directly connect with the client).

SpringBoot uses Netty to implement remote calls

maven dependency

<!--lombok-->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.2</version>
  <optional>true</optional>
</dependency>

<!--netty-->
<dependency>
  <groupId>io.netty</groupId>
  <artifactId>netty-all</artifactId>
  <version>4.1.17.Final</version>
</dependency>

Server part

NettyServer.java: service startup listener

@Slf4j
public class NettyServer {
    public void start() {
        InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8082);
        //new a main thread group
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        //new a worker thread group
        EventLoopGroup workGroup = new NioEventLoopGroup(200);
        ServerBootstrap bootstrap = new ServerBootstrap()
                .group(bossGroup, workGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ServerChannelInitializer())
                .localAddress(socketAddress)
                //Set queue size
                .option(ChannelOption.SO_BACKLOG, 1024)
                // When there is no data communication within two hours, TCP will automatically send an activity detection data message
                .childOption(ChannelOption.SO_KEEPALIVE, true);
        //Bind the port and start receiving incoming connections
        try {
            ChannelFuture future = bootstrap.bind(socketAddress).sync();
            log.info("Server start listening port: {}", socketAddress.getPort());
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("Server startup failed", e);
        } finally {
            //Close main thread group
            bossGroup.shutdownGracefully();
            //Close worker thread group
            workGroup.shutdownGracefully();
        }
    }
}

ServerChannelInitializer.java: netty service initializer

/**
* netty Service initializer
**/
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        //Add codec
        socketChannel.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
        socketChannel.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
        socketChannel.pipeline().addLast(new NettyServerHandler());
    }
}

NettyServerHandler.java: netty server processor

/**
* netty Server processor
**/
@Slf4j
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    /**
     * Client connection triggers
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("Channel active......");
    }

    /**
     * When the client sends a message, it will trigger
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.info("The server received a message: {}", msg.toString());
        ctx.write("You too");
        ctx.flush();
    }

    /**
     * Abnormal trigger occurred
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

RpcServerApp.java: SpringBoot startup class

/**
* Startup class
*
*/
@Slf4j
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class RpcServerApp extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(RpcServerApp.class);
    }

    /**
     * How to start the project
     *
     * @param args
     */
    public static void main(String[] args) {
        SpringApplication.run(RpcServerApp.class, args);
        //Turn on Netty service
        NettyServer nettyServer =new  NettyServer ();
        nettyServer.start();
        log.info("======Service started========");
    }
}

Client part

NettyClientUtil.java: NettyClient tool class

/**
* Netty client
**/
@Slf4j
public class NettyClientUtil {

    public static ResponseResult helloNetty(String msg) {
        NettyClientHandler nettyClientHandler = new NettyClientHandler();
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap()
                .group(group)
                //The function of this parameter is to prohibit the use of Nagle algorithm for real-time transmission of small data
                .option(ChannelOption.TCP_NODELAY, true)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast("decoder", new StringDecoder());
                        socketChannel.pipeline().addLast("encoder", new StringEncoder());
                        socketChannel.pipeline().addLast(nettyClientHandler);
                    }
                });
        try {
            ChannelFuture future = bootstrap.connect("127.0.0.1", 8082).sync();
            log.info("Client sent successfully....");
            //send message
            future.channel().writeAndFlush(msg);
            // Wait for the connection to be closed
            future.channel().closeFuture().sync();
            return nettyClientHandler.getResponseResult();
        } catch (Exception e) {
            log.error("client Netty fail", e);
            throw new BusinessException(CouponTypeEnum.OPERATE_ERROR);
        } finally {
            //Thread exit in an elegant way
            group.shutdownGracefully();
        }
    }
}

NettyClientHandler.java: client processor

/**
* Client processor
**/
@Slf4j
@Setter
@Getter
public class NettyClientHandler extends ChannelInboundHandlerAdapter {

    private ResponseResult responseResult;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("client Active .....");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.info("Client received message: {}", msg.toString());
        this.responseResult = ResponseResult.success(msg.toString(), CouponTypeEnum.OPERATE_SUCCESS.getCouponTypeDesc());
        ctx.close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

verification

Test interface

@RestController
@Slf4j
public class UserController {

    @PostMapping("/helloNetty")
    @MethodLogPrint
    public ResponseResult helloNetty(@RequestParam String msg) {
        return NettyClientUtil.helloNetty(msg);
    }
}

Access test interface

Server printing information

Client print information

Author: Xiyuan's wonderful ideas

Share the answers to this interview and the collected interview questions that must be asked by large manufacturers:

   return NettyClientUtil.helloNetty(msg);
}

}

Access test interface

[External chain picture transfer...(img-p980MOVn-1623617592124)]

Server printing information

[External chain picture transfer...(img-K6besFit-1623617592126)]

Client print information

[External chain picture transfer...(img-lmPBltyE-1623617592127)]

> Author: Xiyuan's wonderful ideas 
# Share the answers to this interview and the collected interview questions that must be asked by large manufacturers:

[External chain picture transfer...(img-AMLE7k5o-1623617592128)]

**[Data collection method: you can download it for free by stamping here](https://docs.qq.com/doc/DSmxTbFJ1cmN1R2dB)**

Topics: Java Interview Programmer