这个模式是高并发服务器的基础,如Nginx和lighttpd。这两种对大并发,但每个请求处理都很快的场景非常适合。通常的web访问就是这个特点。
结构
包括了5个部分,其中handle和Synchronous Event Demultiplexer有OS实现。
Handles:
论文中使用的是单线程模型,即一个线程同时处理接受请求和处理请求。该模型中,如果每个请求的处理时间较长,则会影响真个系统的吞吐率。
就是网络连接(connection),每个网络连接都由一个handle表示。
Event(事件)
ACCEPT_EVENT:表示收到连接请求
READ_EVENT:表示收到数据
WRITE_EVENT:表示socket可以足够的缓冲区,可以向其写入数据。
TIMEOUT_EVENT:超时。Java NIO不支持这个事件。
SIGNAL_EVENT:信号。Java NIO不支持这个事件。
Event Handler
事件处理代码,该对象实例(instance)是和handle关联的。每个Event Handler处理一个handle上的事件。一般的服务器中至少有两种事件处理代码:一个是用来接收连接请求(accept event handler),响应ACCEPT_EVENT。,一个用来处理接受的请求(connection event handler),响应READ_EVENT和WRITE_EVENT。
Synchronous Event Demultiplexer(事件多路分离系统)
该模式的核心,等待handles上的事件。没有事件出现时,一直阻塞(blocking);当某个(某些)handles上有时间产生时,返回。这个是实现一般由操作系统提供,如linux的select、poll及epoll等。
Initiation Dispatcher
内部使用Synchronous Event Demultiplexer
reactor的论文中给出了实例代码
Logging_Acceptor是处理接收请求的event handler。
Logging_Handler是处理实际请求的event handler
Initiation_Dispatcher::instance是单利模式的Initiation Dispatcher
线程模型
更为普遍的是使用多线程模型。多线程的基本方式是1:n。
1个线程用来接受连接请求,执行accept event handler。
其他的线程用来处理连接请求,执行connection event handler。n的数量可以根据运行情况动态调整。如果每个连接的处理非常快,可能一个线程就够了;如果处理的时间很长,则可能一个连接就要有一个线程。
java NIO
java nio就是依照reactor模式设计的。java nio中的主要抽象:
Selector:相当于Synchronous Event Demultiplexer
SelectionKey: 相当于event,和一个SocketChannel关联
SocketChannel:相当于handle
SocketChannel:相当于handle
netty
作为API,java nio不会设计的很全面,只会提供基本的功能。对一般的用户来说,java nio提供的编程界面还是比较原始(pirmitive),不是很容易使用。netty是一个网络编程框架,在java nio的基础上提供了更高层的抽象。netty的编程比起nio有极大的简化。netty中提供了reactor的所有封装,用户在使用中只需实现event handler即可。
netty在event handler上又提供了一层抽象,ChannelPipeline和ChannelHandler。
ChannelPipeline类似于原来的event handler,用来处理连接请求。ChannelPipeline由若干个ChannelHandler构成,ChannelPipeline会分别调用这些ChannelHandler来处理连接请求。这种设计类似于servlet中的filter chain。所有的ChannelHandler和在一起,形成了处理链路。
netty同样提供了对线程模型的支持,具体可以参考netty的文档。
proactor和reactor的区别