文章目录
- 概述
- 单Reactor单线程模型
- 单Reactor多线程模型
- 主从Reactor多线程模型
概述
Netty的线程模型采用了Reactor模式,即一个或多个EventLoop轮询各自的任务队列,当发现有任务时,就处理它们。Netty支持单线程模型、多线程模型和混合线程模型等多种线程模型。
Reactor其实是在NIO多路复用的基础上提出的一个高性能IO设计模式。
它的核心思想是把响应IO事件和业务处理进行分离,通过一个或者多个线程来处理IO事件。
然后把就绪的事件分发给业务线程进行异步处理。
Reactor模型有三个重要的组件:
Reactor :把I/O事件分发给对应的Handler
Acceptor :处理客户端连接请求
Handlers :执行非阻塞读/写,也就是针对收到的消息进行业务处理。
在Reactor的这种设计中,有三种模型分别是
单Reactor单线程模型
单Reactor多线程模型
主从Reactor多线程模型
单Reactor单线程模型
就是由同一个线程来负责处理IO事件以及业务逻辑。
这种方式的缺点在于handler的执行过程是串行,如果有任何一个handler处理线程阻塞,就会影响整个服务的吞吐量。
理论上一个NIO线程,既能够接收客户端的链接,同时也能够处理IO操作以及其他任务操作等等,但是一个线程对cpu利用率不高,并且,一旦有大量的请求连接,性能上势必会下降,甚至无法响应的情况.
单Reactor多线程模型
也就是把处理IO就绪事件的线程和处理Handler业务逻辑的线程进行分离,每个Handler由一个独立线程来处理,在这种设计下,即便是存在Handler线程阻塞问题,也不会对IO线程造成影响。
在多线程Reactor模型下,所有的IO操作都是由一个Reactor来完成的,而且Reactor运行在单个线程里面。对于并发较高的场景下,Reactor就成为了性能瓶颈,所以在这个基础上做了更进一步优化。
1个线程负责专门接收客户端的链接,另一组线程负责处理IO操作或者其他的任务操作.虽然如此,但理论上来说依然有一个地方是单点的;那就是处理客户端连接的线程。
因为大多数服务端应用或多或少在连接时都会处理一些业务,如鉴权之类的,当连接的客户端越来越多时这一个线程依然会存在性能问题。
主从Reactor多线程模型
提出了多Reactor多线程模型,这种模式也叫Master-Workers模式。
它把原本单个Reactor拆分成了Main Reactor和多个SubReactor,Main Reactor负责接收客户端的
链接,然后把接收到的连接请求随机分配到多个subReactor里面。SubReactor负责IO事件的处理。
这种方式另外一个好处就是可以对subReactor做灵活扩展,从而适应不同的并发量,解决了单个Reactor模式的性能瓶颈问题。
Reactor模型的设计比较常见,比如Spring里面的Webflux就用了这种设计。
并且像Master-Worker模型,在Memcached和Nginx中都有用到。
所以我们其实可以去理解并学习这种设计思想,也许在某些业务场景中可以帮助我们多提供一个解决思路。
Main Reactor:负责接收客户端的连接请求,并将具体的业务IO处理请求转发给 Sub Reactor(其中Sub Reactor可以有多个)。
Acceptor:请求接收者,它的职责类似服务器,并不真正负责连接请求的建立,而只将其请求委托 Main Reactor 线程池来实现,起到一个转发的作用。
Sub Reactor:负责数据的读写,在 NIO 中 通常注册通道的读事件(OP_READ)和写事件(OP_WRITE)。
一个NIO线程池处理链接监听,一个线程池处理IO操作,并且在netty官方中,强烈推荐使用这种线程模型.
Netty有两组线程池,
一个Boss Group,它专门负责客户端连接,另一个Work Group,专门负责网络读写;
Boss Group和Work Group的类型都是NIOEventLoopGroup;NIOEventLoopGroup相当于一个事件循环组,这个组包含了多个事件循环,每一个循环都NIOEventLoop;NIOEventLoop表示一个不断循环执行处理任务的线程,每个NIOEventLoop都有一个Selector,用于监听绑定在其上的ocketChannel的网络通讯;Boss Group下的每个NIOEventLoop的执行步骤有3步:(1). 轮询accept连接事件;(2). 处理accept事件,与client建立连接,生成一个NioSocketChannel,并将其注册到某个work group下的NioEventLoop的selector上;(3). 处理任务队列的任务,
即runAllTasks每个Work Group下的NioEventLoop循环执行以下步骤:(1). 轮询read、write事件;(2). 处理read、write事件,在对应的NioSocketChannel处理;(3). 处理任务队列的任务,即runAllTasks;每个Work Group下的NioEventLoop在处理NioSocketChannel业务时,会使用pipeline(管道),管道中维护了很多 handler 处理器用来处理 channel 中的数据。