vlambda博客
学习文章列表

谈谈你对Reactor模型的理解?


本篇文章大概1500字,阅读时间大约7分钟


本篇文章是对前面Netty的线程图像相关文章的一个重新总结,并修改了一些错误,还是希望用面试题的形式来全面总结Netty的设计思想和使用的细节,本文主要是重点review了reactor模型的设计

谈谈你对Reactor模型的理解?

回顾Netty服务端最简demo:

谈谈你对Reactor模型的理解?

要启动一个Netty服务端,最小结构必须指定三类属性,分别是:

1、线程模型

2、I/O模型

3、客户端连接读、写处理逻辑,其实也可以不写,但这样的话,这个服务器就没什么意义了


有了这三者,在使用服务端引导器serverBootstrap调用bind(xxx),就可以绑定一个端口,将Netty服务端启动


整个流程抽象如下:

一定是一个服务端端口对应一个NIO线程,即所谓的reactor线程,即Netty的新连接接入线程池,它针对一个端口一定只启动一个NIO线程,即使你设置多个也没有用。该线程只监听一个事件——OP_ACCEPT,即新连接接入事件,当触发该I/O事件后,Netty服务端的Channel底层封装的JDK的ServerSocketChannel就会接收该连接,该过程永远不会阻塞,并实例化一个Netty客户端的Channel,底层是JDK的SocketChannel,此后通过pipeline机制,迅速将新连接传递,如此一来该reactor线程就不会阻塞,可以源源不断的响应新连接,节省了大量线程,如果是传统的阻塞式网络编程,那么这里的接入线程池会启动大量线程,即一个线程对应一个网络连接,如下是Netty的一个处理流程图:

谈谈你对Reactor模型的理解?

新连接被传递到pipeline上,本身是触发channelRead方法,即一个入站事件,最后会进入新连接接入器,在该接入器内,新连接被各种加工,然后为其分配一个新的I/O线程池里的线程,该线程专门处理当前Channel上的读写事件,至于其他耗时业务逻辑,一般都是单独开一个业务线程池处理,如此一来整个流程都不会发生无意义的阻塞。至于这些读写的数据就是通过Netty的Bytebuf组件管理的,即Netty的内存图像。


后续会反复看到该图,先看所谓的reactor模型到底是什么。在我看来,Reactor模型本质就是一个死循环+I/O多路复用,如下demo,它的代码表现基本就是这样:

while(true){ xxx = selector.select(); ... }

因为它会源源不断的产生新的I/O事件,所以被称作反应堆(reactor)是很贴切的形容。


常见的reactor模型有三类(这里摘抄了网络的几个图,画的很好,没必要重画了,侵删):


1、单线程模型

谈谈你对Reactor模型的理解?

如上,整个流程中就有一个NIO线程,而且充当的是reactor角色,它即处理接入的新连接,也处理新连接上的读写事件,handler是一个个的业务处理器,它们都在一个I/O线程中执行。看起来线程数很少很高效,但是这个模型的缺陷是其中某个handler的流程阻塞会导致其他的客户端连接上的handler都得不到执行,并且更严重的问题是:当N个handler长时间阻塞,会导致整个服务不能接收新的外部请求,因为acceptor处理单元也被阻塞了。因此单线程Reactor模型用的比较少,仅仅是理论设计。


2、多线程模型

谈谈你对Reactor模型的理解?

多线程模型与单线程模型的区别是:多线程reactor模型的acceptor是一个单独的NIO线程。即acceptor只用于监听客户端连接请求。而具体的业务处理交给一组特定的NIO线程负责,即各个客户端连接的I/O操作交给其它的线程池,其中每个客户端连接都与线程池中的一个NIO线程绑定,因此在这个客户端连接中的所有I/O操作都是在同一个线程中完成。客户端连接有很多,但NIO线程数比较少,因此一个NIO线程可以同时绑定到多个客户端连接中,反之不行,它们属于一对多的关系。


3、主从多线程模型

谈谈你对Reactor模型的理解?

如果服务器需要同时处理大量客户端连接请求,或需要在客户端连接时进行一些权限的检查,那么单线程的acceptor很有可能就处理不过来,会造成大量的客户端不能连接到服务器的现象。主从多线程模型就是在这样的情况下提出来的,它的特点是服务器端接收客户端的连接请求不再是一个线程,而是由一个独立的线程池组成,同时监听多个服务端口,这样能处理更多的新连接接入,同样的,handler处理仍然是由一个单独的NIO线程池负责。补充参考:



事实上,一般情况下Reactor的多线程模型已经可以很好的工作了,主从模型用的也不多,没必要。Netty服务端编码实现就是采用了第二种,即多线程reactor模型,只需要监听一个端口,即一个服务器端口对应一个reactor线程。


END


点亮在看,你最好看

~

阅读原文,获得更多精彩内容