彻底搞懂Netty的线程模型

2,256 阅读4分钟

前言

Netty是基于异步的事件驱动的高性能网络框架和工具,常见的分布式中间件底层都有涉及到Netty。

要学习netty线程模型,先了解三种IO模型,这样理解netty线程模型和IO模型更轻松。

BIO

同步阻塞IO模型

  • 一个线程负责连接,多线程则为每一个接入开启一个线程
  • 一个请求一个应答
  • 请求之后应答之前客户端会一直阻塞

NIO

同步非阻塞I/O

基于IO多路复用技术的“非阻塞同步”IO模型。简单来说,内核将可读可写事件通知应用,由应用主动发起读写操作;

AIO

异步非阻塞IO,AIO 引入异步通道的概念,采用了 Proactor 模式,简化了程序编写,有效的请求才启动线程,它的特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间较长的应用

NIO和AIO不同之处在于应用是否进行真正的读写操作。

netty的线程模型是基于reactor模式的一种实现,所以了我们先来了解一下reactor的三种线程模型

Reactor三种线程模型

Reactor单线程模型

指所有的 I/O 操作都在同一个 NIO 线程上面完成的,此时NIO线程职责包括:

  • 作为NIO服务端,接收客户端的TCP连接
  • 作为NIO客户端,向服务端发起TCP连接
  • 读取通信对端的请求或者应答消息
  • 向通信对端发送消息请求或者应答消息

Reactor 为单个线程,如上图所示:不仅需要处理客户端的 accept 连接请求,同时也要负责分发(dispatch)读写请求到处理器中。

这样会导致的缺点也很明显

  1. 性能无法支撑一个NIO线程同时处理成百上千的链路
  2. 一旦NIO线程挂了,整个IO模型就会不可用,直接down掉

一个线程负责所有事情

Reactor多线程模型

Reactor多线程模型与单线程模型最大区别就是一组NIO线程处理I/O操作,一个NIO线程处理Accept。一个NIO线程可以处理多个连接事件,一个连接的事件只能属于一个NIO线程。

将非IO事件交由线程池处理,reactor线程负责io事件

在绝大多数场景下,Reactor 多线程模型可以满足性能需求。

但是,当客户端短时间内连接请求爆表的时候,单个 Rector 不仅要处理注册事件,也要同时分发任务到 worker 线程池,分发是比较耗时的操作,单独一个 Acceptor 线程可能会存在性能不足的问题,有可能会导致阻塞。

Reactor主从多线程模型

服务端用于接收客户端连接的不再是一个单独的 NIO 线程,而是一个独立的 NIO 线程池

主reactor接受的请求给到从reactor后,全部走线程池,这样即使几十万个请求同时到来也是可以支撑的。

主reactor负责接收链接,从reactor负责传递io事件到线程池

Netty线程模型

首先需要明确的一点是

「Netty的线程模型并不是一成不变的,它实际取决于用户的启动参数配置。通过设置不同的启动参数,Netty 可以同时支持 Reactor 单线程模型、多线程模型。」

Netty默认的线程模型就是上面的主从NIO模型,是基于Reactor模型的。通常采用一主多从,但是也可以根据实际需要配置启动参数改成 “多主多从”。

我们通过代码可以很直观的了解Netty的线程模型

单线程模型:

private EventLoopGroup group = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap()
                .group(group)
                .childHandler(new HeartbeatInitializer());

多线程模型:

private EventLoopGroup boss = new NioEventLoopGroup(1);
private EventLoopGroup work = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap()
                .group(boss,work)
                .childHandler(new HeartbeatInitializer());

主从多线程:

private EventLoopGroup boss = new NioEventLoopGroup();
private EventLoopGroup work = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap()
                .group(boss,work)
                .childHandler(new HeartbeatInitializer());

大伙可以需要根据具体的业务场景进行判断,灵活处理。

我的微信公众号:Java架构师进阶编程
专注分享Java技术干货,包括JVM、SpringBoot、SpringCloud、数据库、架构设计、面试题、电子书等,期待你的关注!