「我正在参与掘金会员专属活动-源码共读第一期,点击参与」
本文谈一下我对Reactor线程模型的理解,内容包括Reactor线程模型是什么、有哪几种分类、Netty中的类分别对应Reactor线程模型中的哪些角色。
一、Reactor线程模型是什么
Reactor模型翻译过来是“反应器”模型,它还有另一个名字-Dispatcher模型即”分派器“模型,个人觉得”分派器“这个名字更容易理解。
该模型的特点就是基于IO多路复用与事件机制,通过Reactor对IO事件(accept事件、read事件)进行分派,交给不通的Handler进行处理。
上面的表述中出现了Reactor与Handler两种角色,一种比较容易的理解方式:可以认为Reactor是“分活的”,Handler是“干活的”。
二、Reactor模型分类
单Reactor单线程/进程
在该种模型下,虽然可能仍然对Reactor与Handler的角色进行了区分,但他们做的工作都在同一个线程或进程中,也就是accept、读、写同一个线程或进程中处理。
这种模型的好处就是实现简单,不需要维护线程池,也避免了任何形式的多线程数据竞争。
它的缺点也比较明显,因为所有事件都在单个线程内处理,耗时的读操作会影响accept新连接。
使用单Reactor单进程的知名软件有Redis,我们知道在使用Redis时要尽量避免使用keys命令,正是因为它的单进程模型特点,要求使用者避免单条命令消耗太长的时间,这会影响其它连接的使用。
单Reactor多线程/进程
单Reactor多线程模型增加了线程的数量,将耗时的读操作与业务处理放到其他线程去做,这大大缓解了单Reactor单线程模型的问题。

但是在该模型下Reactor仍要负责分派所有的accept事件与读就绪事件,在高并发场景下Reactor的线程仍有可能成为性能瓶颈。于是多Reactor多线程模型产生了。
多Reactor多线程/进程
在多Reactor多线程模型中,增加了subReactor的角色。
将IO事件交由多个Reactor分派,mainReactor只负责处理accept事件,subReactor负责分派读事件。
mainReactor在accept新的连接后会将SocketChannel注册到subReactor上。
在并发高的情况下还可以增加subReactor的数量,充分利用cpu资源。
三、Netty中的Reactor模型
Netty中的类分别对应Reactor模型中的哪些角色呢?
使用Netty服务端时会调用serverBootstrap.group方法去设置bossGroup和workGroup,这两个NioEventLoopGroup类型的对象就分别对应了mainReactor和subReactor。
向NioServerSocketChannel添加的ServerBootstrapAcceptor是负责accept连接的Handler。
向NioSocketChannel添加的childHandler就是负责后续读写的handler。
四、总结与思考
在使用与网络IO打交道的框架或程序时,去分辨和理解它的线程模型是很有必要的。
例如使用单Reactor单线程模型的程序,就需要使用者自己注意去控制单次操作的消耗,否则很容易影响其它连接的处理。
在使用多Reactor多线程模型时,要能根据机器配置、程序的并发需求、真实的访问量去调整Reactor数量,调整Reactor线程池的参数。
这些都依赖我们在对程序的线程模型有较好的理解。