Reactor和PReactor线程模型

Posted by LiuXi on 2017-11-07

前面两篇文章中主要归纳了五种I/O模型(阻塞I/O模型、非阻塞I/O模型、I/O多路复用模型、基于信号量的I/O模型和异步I/O模型),以及java对各种I/O模型的支持(BIO、NIO 和 AIO)。

对于服务端应用来说,需要对用户和其他系统提供多种服务。而服务的调用,流程一般为接收请求、处理和发送响应,其实就是I/O操作和逻辑处理。在互联网应用中,随着服务调用并发量的持续增长,针对不同的I/O模型,一般也需要从线程模型的角度来优化处理流程,保证服务处理的性能。

下面主要说明下JAVA BIO、NIO 和 AIO 这三种I/O模型对应的线程模型

其实也不仅仅局限于JAVA,线程模型的思路都是可以相通的,只不过对于熟悉JAVA的人来说,结合JAVA I/O来理解线程模型,能更加了解线程模型的处理方式

线程模型的选择都是为了处理更高的并发量,即下面讨论的基础是更加高效的处理持续增长的并发请求。

1 阻塞I/O线程模型

对于阻塞I/O来说,服务器接收到一个服务调用后,会分配一个线程,处理服务请求的整个流程接收请求、处理和发送响应。而对于这种简单的I/O模型来说,程序的处理流程比较简单,顺序执行即可,那么这种I/O模型需要什么样线程处理模型呢?

由于每个服务调用都会创建一个线程,并发量持续增加时,线程的数量也会持续增加,此时,不管是线程创建和销毁的开销、线程上线文切换的开销还是硬件的限制,都不能满足请求的高效处理。

这种情况下,可以采取线程池的方式处理请求,限制了线程数量的上线,也能复用线程减少线程销毁和创建的开销和线程上线文切换的开销。

2 Reactor模型

Reactor – 反应堆

对于NIO(I/O多路复用模型)来说,由I/O多路复用器Selector来管理大量的I/O操作,I/O多路复用器Selector负责注册和监听I/O事件,当有事件触发是,调用相应的逻辑处理流程,这种I/O模型又演化出什么样的线程模型呢?

2.1 定义

Reactor 模型:一种事件驱动的线程模型,用于同步I/O(JAVA NIO,多路复用I/O模型),将I/O事件注册到多路复用器Selector上,I/O线程轮询事件,当有I/O事件触发,多路复用器将事件分发到相应的工作线程中进行处理。

从上面可以看出,重点是I/O线程和工作线程。I/O线程负责注册和监听I/O事件。工作线程负责处理I/O事件。

2.2 角色

在探讨不同的Reactor线程模型前,先明确下Reactor模型中涉及的几个角色:

  • Reactor(Dispatcher):将I/O事件分发给对应的工作线程处理器Handler
  • Acceptor:处理客户端的连接请求
  • 工作线程处理器Handler:处理I/O事件

2.3 分类

在Reactor模型中根据给不同的角色分配不同的线程可以将Reactor模型分为:Reactor单线程模型、Reactor多线程模型和主从Reactor多线程模型

2.3.1 Reactor单线程模型

Reactor单线程模型是指Reactor、Acceptor和Handler三个角色在同一个线程中,即多路复用器阻塞轮询事件,事件触发后,调用相应的handler处理。

Reactor单线程模型适用于handler处理耗时较少的场景和并发请求量不是特别大的场景,若handler处理耗时较长,会影响后续事件的处理,从而降低了整体的处理效率

2.3.2 Reactor多线程模型

Reactor单线程模型中I/O读写和数据处理属于同步操作,在同一个线程中处理,无法处理大量的连接,为了不影响Acceptor线程处理客户端连接,可以将Acceptor线程和I/O处理线程分离开来。

如上图,Acceptor分配单独的线程,完成客户端连接请求处理和事件监听,I/O事件触发后,将事件分发给Handler线程池进行处理(包含I/O读写),这就是Reactor多线程模型

2.3.3 主从Reactor多线程模型

主从Reactor多线程模型分为Main Reactor线程池、Sub Reactor线程池和工作线程池(不包含I/O读写)。

  • Main Reactor线程池:线程池中包含多个Acceptor线程,完成客户端的连接请求
  • Sub Reactor线程池:线程池中的线程主要负责处理I/O事件,完成I/O读写操作和数据的编码解码
  • 工作线程池:完成数据的处理

下面看下这种线程模型解决了什么问题:

  • Main Reacto线程(Acceptor线程)池化,为了解决单Acceptor线程处理大量连接的效率问题
  • Sub Reactor线程池完成I/O读写和编码解码,将这部分任务从工作线程handler中剥离出来
  • 工作线程池不负责I/O相关,只处理目标数据类型的数据,处理请求是无需关心解码,发送响应时无需关心编码

3 PReactor模型

PReactor模型是真正的异步模型,用于异步I/O(JAVA AIO),执行I/O操作时,提交回调处理函数,I/O操作完成后由操作系统自动完成回调函数的调用。

PReactor模型中的回调函数,可以是事件分发器,根据不同的连接的I/O操作,分发给相应的工作线程进行处理。

PReactor屏蔽了操作系统支持异步I/O的细节,应用无需显示地创建异步线程,只需关心I/O操作完成后的业务逻辑。

4 Reactor模型与PReactor模型的区别

  • I/O模型:Reactor模型用于同步I/O(I/O多路复用);PReactor模型用于异步I/O

  • 处理流程:
    Reactor模型多路复用器监听事件,事件触发后,分发事件,然后同步读写数据,处理数据
    PReactor模型异步化处理,无需监听事件

  • 异步化问题:
    Reactor模型中将I/O操作(包括读写数据)交由单独的I/O线程,工作线程只处理目标数据,不关心I/O操作,对于工作线程来说,也可以理解为异步化,但是其实只是模拟异步化,并不是真正的异步I/O
    PReactor模型是从异步I/o模型层面,操作系统本身实现的异步化

5 参考文档

http://www.uml.org.cn/j2ee/2014060411.asp
http://blog.csdn.net/u013074465/article/details/46276967
http://www.jasongj.com/java/nio_reactor/