Netty线程模型

43 阅读3分钟

一、传统IO线程模型的劣势

在NIO出现之前,我们使用的其实都是传统的IO模型

public static void main(String[] args) throws IOException {
    ServerSocket serverSocket = new ServerSocket(8088);

    new Thread(() -> {
        try {
            Socket accept = serverSocket.accept();
            new Thread(() -> {
                try {
                    int len;
                    byte[] data = new byte[1024];
                    InputStream inputStream = accept.getInputStream();
                    while ((len = inputStream.read(data)) != -1) {
                        System.out.println(new String(data, 0, len));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }).start();
}

上述代码处理连接时,只能由一个线程处理一个连接,意味着如果有1000个客户端连接就得开1000个线程。且在每次线程使用完之后都需要销毁,这无疑是影响性能的,且频繁的线程上下文切换也是不合理的。而在传统IO的处理中我们无非是使用线程池替换传统线程的创建和销毁,但是这也没有从根本上改变这一问题

二、Reactor模型

Reactor模型是一种常用的高性能IO模型,一种异步、非阻塞的事件驱动的模型,有三种实现方式

2.1 基于单线程实现

image.png 上面图中描述的就是单线程实现Reactor,由一个线程来接收客户端连接,通过dispatcher将对应的请求数据分发到指定的handler进行编码处理,对于并发小的场景可以适用。但是在高并发情况下这种模型还是无法满足的,其原因在于:

  1. 单线程NIO无法支撑过多的连接接入
  2. CPU负载过高,处理就会变慢,就会造成大量客户端连接超时
  3. 低可靠性,如果出现死循环那么整个功能将不可用
  4. 无法利用多核CPU的优势,造成资源浪费

2.2 Reactor多线程实现

image.png 多线程实现实际上是优化了原先只有一个线程处理事件带来的弊端,可以基于java自身的线程池实现,其变化在于,连接进来时,会将其分配到对应的线程,由对应的线程进行处理,在处理连接时使用的依旧时单线程

2.3 主从多线程

image.png 优化连接处理部分,使用多线程,当一个客户端连接进来时,主线程池会选出一个NIO线程,充当Acceptor,负责处理新接入的连接。连接创建完成之后,使用Dispatcher派发到主线程池,主线程池将新连接绑定到从线程池的一个NIO线程并处理后续读写操作

三、Netty对三种线程模型的支持

  1. 单线程模式
public ServerBootstrap group(EventLoopGroup group) {
    return group(group, group);
}
  1. 多线程和主从多线程模式 image.png image.png
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
    super.group(parentGroup);
    if (childGroup == null) {
        throw new NullPointerException("childGroup");
    }
    if (this.childGroup != null) {
        throw new IllegalStateException("childGroup set already");
    }
    this.childGroup = childGroup;
    return this;
}

在构建ServerBootstrap实例时,传入单个NioEventLoopGroup对象构建的是单线程的,传入worker和boss两个NioEventLoopGroup构建的是多线程的,指定boss这个NioEventLoopGroup的线程数或者不传(依据当前计算机CPU核数决定构建的线程池大小)则构建的是主从多线程模式