Netty的基本概念

使用Netty(NIO框架)完成一次RPC通信,相比传统基于Java序列化+BIO的RPC通信框架,其通信性能可以提升8倍多。

传统RPC调用性能差的原因

1、网络传输方式存在弊端
  传统的RPC框架都是采用BIO,当客户端的并发压力或网络时延增大时,BIO会因频繁的“wait”导致I/O线程经常出现阻塞的情况,线程本身无法高效地工作,I/O处理能力自然下降。
2、序列化方式存在弊端
  Java序列化是针对对象(Object)设计的编解码技术,无法跨语言使用。因此无法支持在异构系统之间对接,无法将Java序列化后的字节码流反序列化成原始对象。
  相比其他开源的序列化框架,Java序列化后的字节码流占用的空间太大,无论是传输还是持久化到磁盘,都会增加资源的消耗。
  序列化性能差,在编解码过程中需要占用更高的CPU资源。
3、线程模型存在弊端
  BIO模型使得每个TCP连接都需要分配1个线程,而线程资源是JVM宝贵的资源,当I/O读写阻塞导致线程无法及时释放时,系统性能急剧下降,甚至导致JVM无法创建新线程。

Netty高性能原因
1、I/O传输模型
I/O传输模型在很大程度上决定了框架的性能。Netty使用了NIO模型
2、数据协议
一般来说内部私有协议比公有协议的性能更高。
3、线程模型
线程模型设计如何读取数据包,读取之后的编解码在哪个线程中进行,编解码后消息如何派发等。

1、Reactor线程模型与NioEventLoopGroup

Netty是Reactor模型的一个实现。Reactor的线程模型有三种:单线程模型,多线程模型,主从多线程模型。

1.1 单线程模型

  单线程模型,即Acceptor的处理和Handler的处理都在同一个线程中。这种模型弊端是:当其中某个Handler阻塞时,会导致其他所有的Handler都无法执行,也会导致整个服务不能接收新的Client请求,因为Acceptor也被阻塞了。因此这种模型应用较少。
在这里插入图片描述
  单线程模型在Netty中的应用代码如下。

EventLoopGroup bossGroup = new NioEventLoopGroup(1);
ServerBootstrap server = new ServerBootstrap();
server.group(bossGroup);

  上面代码中,首先实例化一个NioEventLoopGroup,然后调用server.group(bossGroup),设置服务端的EventLoopGroup 。在启动服务端的Netty程序时,需要设置bossGroup和workerGroup,这里只设置一个bossGroup,原因是ServerBootstrap重写了group方法,代码如下。当传入一个group时,bossGroup和workerGroup是同一个NioEventLoopGroup,并且由于NioEventLoopGroup只设置一个线程,因此Netty的Acceptor和后续的客户端连接的I/O操作都是在一个线程中处理的。因此这样设置,对应的就是Reactor的单线程模型。

public ServerBootstrap group(EventLoopGroup group) {
    return this.group(group, group);
}

1.2 多线程模型

  多线程模型,设计一个专门的线程Acceptor用于监听客户端的TCP连接请求,I/O操作由特定的NIO进程池负责,每个客户端都和一个特定的NIO线程绑定,这个客户端的所有I/O操作都是在同一个线程中完成的。需要注意的是,NIO线程数较少,客户端连接很多时,一个NIO线程可以同时绑定多个客户端连接中。
在这里插入图片描述
  多线程模型在Netty中的应用代码如下,只需要将bossGroup的参数设置为大于1的数,就是Reactor多线程模型。

EventLoopGroup bossGroup = new NioEventLoopGroup(128);
ServerBootstrap server = new ServerBootstrap();
server.group(bossGroup);

1.3 主从多线程模型

  一般情况下,Reactor的多线程模型已经适用于大部分业务场景,但是如果需要同时处理大量的客户端连接请求,或者需要在客户端连接时增加一些例如权限校验等操作,那么单个Acceptor有可能处理不过来,将会造成大量的客户端连接超时。
  主从多线程模型,将服务端接收客户端的连接请求专门设计一个独立的线程池。
在这里插入图片描述
  主从Reactor多线程模型在Netty的应用代码如下,bossGroup为主线程,而workerGroup的线程数是CPU核数×2,对应到主从Reactor多线程模型。

EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup);

2、服务端ServerBootstrap

  1、服务端指定两个EventLoopGroup,一个是bossGroup,处理客户端的连接请求,另一个是workerGroup,用于处理与各个客户端连接的I/O操作。
  2、指定Channel的类型,这里是服务端,所以使用NioServerSocketChannel,用于异步非阻塞的服务端TCP Socket连接。Channel是对Java底层Socket连接的抽象。
  3、配置自定义的业务处理器Handler。

public class ChatServer {

    public void start(int port) throws Exception {
        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
                        protected void initChannel(SocketChannel ch) throws Exception {

                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            System.out.println("服务已启动,监听端口" + port + "");
            ChannelFuture f = b.bind(port).sync();
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();

            System.out.println("服务已关闭");
        }

    }

    public static void main(String[] args) {
        try {
            new ChatServer().start(20000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3 客户端Bootstrap

  Bootstrap是Netty的工厂类,可以通过它完成客户端和服务端的Netty初始化。下面代码主要步骤是:
  1、指定客户端的EventLoopGroup,无论是服务端还是客户端,都需要指定EventLoopGroup。
  2、ChannelType,因为是客户端,因此指定NioSocketChannel
  3、设置处理数据的Handler。

public class CharClient {
    public CharClient connect(int port, String host, final String nickName) {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            
                        }
                    });
            ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
        return this;
    }
    public static void main(String[] args) {
        new CharClient().connect(8080, "loalhost", "demo");
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty是一个高性能的网络通信框架,可以用于实现即时通讯(IM)的功能。实现IM主要涉及以下几个方面: 1. 协议设计:首先需要设计一个通信协议,用于客户端和服务器之间的数据交换。协议可以基于TCP或者UDP,也可以使用其他自定义的协议。协议中应包含消息的格式、指令的定义、数据的编码和解码规则等。 2. 服务端编码:使用Netty可以轻松地编写服务端代码。服务端需要监听指定的端口,并处理客户端的请求。Netty提供了ChannelHandler来处理网络事件,可以通过继承ChannelInboundHandlerAdapter类来实现自定义的处理逻辑。在服务端中,可以接收并解析客户端发送的消息,处理消息的逻辑,然后发送响应消息给客户端。 3. 客户端编码:客户端也需要使用Netty框架编写代码。客户端需要与服务端建立连接,并发送请求消息给服务端。Netty提供了ChannelInitializer来进行初始化设置,可以通过继承ChannelInitializer类来配置客户端的ChannelPipeline。在客户端中,通过发送消息给服务端并接收响应消息,实现与服务端的即时通讯。 4. 异步处理:Netty提供了事件驱动的编程模型,可以实现非阻塞I/O操作。通过使用事件循环组(EventLoopGroup)和通道(Channel)的概念,可以实现并发处理多个客户端的请求,提高系统的并发性能。 5. 消息推送:IM系统通常需要支持消息的实时推送功能。可以通过Netty的ChannelGroup来管理多个连接的客户端,可以将消息推送给特定的客户端,也可以广播给所有客户端。 以上是使用Netty实现IM的基本步骤。Netty具有高性能、可扩展性强、易于使用等特点,非常适合用于构建IM系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值