Netty源码阅读系列-Reactor线程模型

「我正在参与掘金会员专属活动-源码共读第一期,点击参与

本文谈一下我对Reactor线程模型的理解,内容包括Reactor线程模型是什么、有哪几种分类、Netty中的类分别对应Reactor线程模型中的哪些角色。

一、Reactor线程模型是什么

Reactor模型翻译过来是“反应器”模型,它还有另一个名字-Dispatcher模型即”分派器“模型,个人觉得”分派器“这个名字更容易理解。

该模型的特点就是基于IO多路复用与事件机制,通过Reactor对IO事件(accept事件、read事件)进行分派,交给不通的Handler进行处理。

上面的表述中出现了Reactor与Handler两种角色,一种比较容易的理解方式:可以认为Reactor是“分活的”,Handler是“干活的”。

二、Reactor模型分类

单Reactor单线程/进程

image.png

在该种模型下,虽然可能仍然对Reactor与Handler的角色进行了区分,但他们做的工作都在同一个线程或进程中,也就是accept、读、写同一个线程或进程中处理。

这种模型的好处就是实现简单,不需要维护线程池,也避免了任何形式的多线程数据竞争。

它的缺点也比较明显,因为所有事件都在单个线程内处理,耗时的读操作会影响accept新连接。

使用单Reactor单进程的知名软件有Redis,我们知道在使用Redis时要尽量避免使用keys命令,正是因为它的单进程模型特点,要求使用者避免单条命令消耗太长的时间,这会影响其它连接的使用。

单Reactor多线程/进程

image.png 单Reactor多线程模型增加了线程的数量,将耗时的读操作与业务处理放到其他线程去做,这大大缓解了单Reactor单线程模型的问题。

但是在该模型下Reactor仍要负责分派所有的accept事件与读就绪事件,在高并发场景下Reactor的线程仍有可能成为性能瓶颈。于是多Reactor多线程模型产生了。

多Reactor多线程/进程

image.png

在多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线程池的参数。

这些都依赖我们在对程序的线程模型有较好的理解。

猜你喜欢

转载自juejin.im/post/7177700850189402171