Reactor模式详解

作者: wiseAaron | 来源:发表于2016-10-18 12:45 被阅读1036次

    什么是Reactor模式

    要回答这个问题,首先当然是求助Google或Wikipedia,其中Wikipedia上说:“The reactor design pattern is an event handling pattern for handling service requests delivered concurrently by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to associated request handlers.”。从这个描述中,我们知道Reactor模式首先是事件驱动的,有一个或多个并发输入源,有一个Service Handler,有多个Request Handlers;这个Service Handler会同步的将输入的请求(Event)多路复用的分发给相应的Request Handler。如果用图来表达:


    Reactor_Simple.png

    从结构上,这有点类似生产者消费者模式,即有一个或多个生产者将事件放入一个Queue中,而一个或多个消费者主动的从这个Queue中Poll事件来处理;而Reactor模式则并没有Queue来做缓冲,每当一个Event输入到Service Handler之后,该Service Handler会主动的根据不同的Event类型将其分发给对应的Request Handler来处理。

    更学术的,这篇文章(Reactor An Object Behavioral Pattern for Demultiplexing and Dispatching Handles for Synchronous Events)上说:“The Reactor design pattern handles service requests that are delivered concurrently to an application by one or more clients. Each service in an application may consistent of several methods and is represented by a separate event handler that is responsible for dispatching service-specific requests. Dispatching of event handlers is performed by an initiation dispatcher, which manages the registered event handlers. Demultiplexing of service requests is performed by a synchronous event demultiplexer. Also known as Dispatcher, Notifier”。这段描述和Wikipedia上的描述类似,有多个输入源,有多个不同的EventHandler(RequestHandler)来处理不同的请求,Initiation Dispatcher用于管理EventHanderEventHandler首先要注册到Initiation Dispatcher中,然后Initiation Dispatcher根据输入的Event分发给注册的EventHandler;然而Initiation Dispatcher并不监听Event的到来,这个工作交给Synchronous Event Demultiplexer来处理。

    Reactor模式结构

    在解决了什么是Reactor模式后,我们来看看Reactor模式是由什么模块构成。图是一种比较简洁形象的表现方式,因而先上一张图来表达各个模块的名称和他们之间的关系:


    Reactor_Structures.png

    Handle:即操作系统中的句柄,是对资源在操作系统层面上的一种抽象,它可以是打开的文件、一个连接(Socket)、Timer等。由于Reactor模式一般使用在网络编程中,因而这里一般指Socket Handle,即一个网络连接(Connection,在Java NIO中的Channel)。这个Channel注册到Synchronous Event Demultiplexer中,以监听Handle中发生的事件,对ServerSocketChannnel可以是CONNECT事件,对SocketChannel可以是READ、WRITE、CLOSE事件等。

    Synchronous Event Demultiplexer:阻塞等待一系列的Handle中的事件到来,如果阻塞等待返回,即表示在返回的Handle中可以不阻塞的执行返回的事件类型。这个模块一般使用操作系统的select来实现。在Java NIO中用Selector来封装,当Selector.select()返回时,可以调用Selector的selectedKeys()方法获取Set<SelectionKey>,一个SelectionKey表达一个有事件发生的Channel以及该Channel上的事件类型。上图的“Synchronous Event Demultiplexer ---notifies--> Handle”的流程如果是对的,那内部实现应该是select()方法在事件到来后会先设置Handle的状态,然后返回。不了解内部实现机制,因而保留原图。

    Initiation Dispatcher:用于管理Event Handler,即EventHandler的容器,用以注册、移除EventHandler等;另外,它还作为Reactor模式的入口调用Synchronous Event Demultiplexer的select方法以阻塞等待事件返回,当阻塞等待返回时,根据事件发生的Handle将其分发给对应的Event Handler处理,即回调EventHandler中的handle_event()方法。

    Event Handler:定义事件处理方法:handle_event(),以供InitiationDispatcher回调使用。
    Concrete Event Handler:事件EventHandler接口,实现特定事件处理逻辑。

    Reactor模式模块之间的交互

    简单描述一下Reactor各个模块之间的交互流程,先从序列图开始:


    Reactor_Sequence.png
    1. 初始化InitiationDispatcher,并初始化一个HandleEventHandlerMap
    2. 注册EventHandlerInitiationDispatcher中,每个EventHandler包含对相应Handle的引用,从而建立HandleEventHandler的映射(Map)
    3. 调用InitiationDispatcherhandle_events()方法以启动Event Loop。在Event Loop中,调用select()方法(Synchronous Event Demultiplexer)阻塞等待Event发生。
    4. 当某个或某些HandleEvent发生后,select()方法返回,InitiationDispatcher根据返回的Handle找到注册的EventHandler,并回调该EventHandlerhandle_events()方法。
    5. EventHandlerhandle_events()方法中还可以向InitiationDispatcher中注册新的Eventhandler,比如对AcceptorEventHandler来,当有新的client连接时,它会产生新的EventHandler以处理新的连接,并注册到InitiationDispatcher中。

    Reactor模式实现

    Reactor An Object Behavioral Pattern for Demultiplexing and Dispatching Handles for Synchronous Events中,一直以Logging Server来分析Reactor模式,这个Logging Server的实现完全遵循这里对Reactor描述,因而放在这里以做参考。Logging Server中的Reactor模式实现分两个部分:Client连接到Logging Server和Client向Logging Server写Log。因而对它的描述分成这两个步骤。
    Client连接到Logging Server

    Reactor_LoggingServer_connect.png
    1. Logging Server注册LoggingAcceptorInitiationDispatcher
    2. Logging Server调用InitiationDispatcher的handle_events()方法启动。
    3. InitiationDispatcher内部调用select()方法(Synchronous Event Demultiplexer),阻塞等待Client连接。
    4. Client连接到Logging Server
    5. InitiationDisptcher中的select()方法返回,并通知LoggingAcceptor有新的连接到来。
    6. LoggingAcceptor调用accept方法accept这个新连接。
    7. LoggingAcceptor创建新的LoggingHandler
    8. 新的LoggingHandler注册到InitiationDispatcher中(同时也注册到Synchonous Event Demultiplexer中),等待Client发起写log请求。
      Client向Logging Server写Log
      Reactor_LoggingServer_log.png
    9. Client发送log到Logging server
    10. InitiationDispatcher监测到相应的Handle中有事件发生,返回阻塞等待,根据返回的Handle找到LoggingHandler,并回调LoggingHandler中的handle_event()方法。
    11. LoggingHandler中的handle_event()方法中读取Handle中的log信息。
    12. 将接收到的log写入到日志文件、数据库等设备中。
      3.4步骤循环直到当前日志处理完成。
    13. 返回到InitiationDispatcher等待下一次日志写请求。

    尊重原著,转载出:http://www.blogjava.net/DLevin/archive/2015/09/02/427045.html
    有关资料:http://www.dre.vanderbilt.edu/~schmidt/PDF/reactor-siemens.pdf

    相关文章

      网友评论

      • must_07d4:channel之间会相互影响吗?使用NIO,Selector上注册了多个channel呀。
        must_07d4:缺点3的观点,有很明显的问题。
      • Chris_R:哈哈哈哈,这本我看过!
        wiseAaron:@五彩的瓜牛 吊吊的

      本文标题:Reactor模式详解

      本文链接:https://www.haomeiwen.com/subject/nzzzyttx.html