手写RPC框架 学习笔记

125 阅读3分钟

手写RPC框架 学习笔记

Netty

Netty是一个高性能的NIO网络编程框架,支持异步和事件驱动。

在学习从0手写一个RPC框架的时候,需要接触使用netty进行通讯

  1. 为什么选择Netty? RPC框架的通讯协议可以选择的有TCP,HTTP,WebSocket,自定义二进制协议等。而大部分RPC框架,是基于TCP传输协议的。HTTP协议是应用层协议,相对于传输层协议TCP,请求头多了更多的复杂字段应用层协议信息等,性能方面差些。Socket和Netty都是基于TCP协议的,Netty对Socket进行了封装,支持同步非阻塞IO,性能较于直接使用Socket好,因此选择Netty作为RPC的网络通讯框架。
  2. OpenFeign是RPC框架么? 以传统RPC框架的定义和概念看,OpenFeign并不能算作是RPC框架,只能算是简化的声明式Restful客户端,它并没有直接通过某种协议进行通讯实现本地直接调用远程服务,而是一种封装代理HTTP请求的客户端去请求远程信息,且性能没有使用传输层协议快,但它确实也能实现远程调用获取某个服务的信息等,但缺乏服务治理之类的能力。

Netty服务端代码说明

EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();

EventLoopGroup理解为一个线程池,用于Netty出现的各种事件处理,服务端一般需要两个EventLoopGroup,bossGroup和workerGroup,bossGroup用于监听客户端的连接事件,workerGroup用于连接客户端后的其他事件处理,例如读写数据等。


try {
    ServerBootstrap serverBootstrap = new ServerBootstrap();
    serverBootstrap.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)
            .option(ChannelOption.SO_BACKLOG, 128)
            .childOption(ChannelOption.TCP_NODELAY, true)
            .childOption(ChannelOption.SO_KEEPALIVE, true)
            .handler(new LoggingHandler(LogLevel.INFO))
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline pipeline = socketChannel.pipeline();
                    pipeline.addLast(new IdleStateHandler(30, 0, 0));
                    pipeline.addLast(new RpcMessageEncoder());
                    pipeline.addLast(new RpcMessageDecoder());
                    pipeline.addLast(serviceHandlerGroup, new NettyRpcServerHandler());
                }
            });
    ChannelFuture channelFuture = serverBootstrap.bind(host, PORT).sync();
    channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
    log.error("occur exception when start server:", e);
} finally {
    log.error("shutdown bossGroup and workerGroup");
    bossGroup.shutdownGracefully();
    workerGroup.shutdownGracefully();
    serviceHandlerGroup.shutdownGracefully();
}
  1. channel()方法指定服务端的channel为NIO的实现,NioServerSocketChannel用于监听服务器端口,接收客户端连接请求,为每个连接创建一个新的NioSocketChannel。
  2. option()方法指定服务端监听的channel属性,SO_BACKLOG是设置请求队列大小的参数。
  3. childOption()方法指定服务端与客户端交互channel属性,TCP_NODELAY和SO_KEEPALIVE分别是设置Nagle算法组合大数据块网络传输和开启TCP心跳机制保证长时间正常连接。
  4. handler()方法设置服务端监听客户端连接之前对channel的处理。
  5. childhandler()方法处理服务端与客户端交互的各种事件channel的处理。
  6. 一个事件对应一个channel,channel中维护一个channelPipeline,channelPipeline中维护一个channelHandler的链表,channel中的数据经过该链表中的handler的各种处理。 channel
  7. channel().closeFuture().sync()的作用是阻塞主线程,防止主线程执行到finally块中,导致Netty关闭。

学习代码来源:github.com/Snailclimb/…