高扩展的基于NIO的服务器架构(二)
Reactor模式
如下图所示,将不同事件的检测分离开,当一种事件发生时一个事件处理器EventHandler将通知与该事件处理相对应的专用工作线程
采用这种架构,连接的通道不得不注册在一个Selector上。这样才能通过调用register方法使通道有效。
未完待续
... SocketChannel channel = serverChannel.accept(); channel.configureBlocking(false); // register the connection SelectionKey sk = channel.register(selector, SelectionKey.OP_READ); ...
为了达到检测新事件的目的,Selector类具备向已注册channel所要它们的就绪事件的能力。通过调用select方法,Selector类收集到了已注册channel的就绪事件。在至少这些就绪事件中的一个事件已经完成之前,select方法是处于阻塞状态下的。这种情况下,select方法返回截至最后一次调用select方法时已经对I/O操作做好准备的连接的数量值。
已选择的连接可以通过调用Selector类的selectedKey方法被检索到。selectedKey方法会返回SelectionKey对象的一个结果集,这些结果集保持了IO事件的状态和连接的Channel的引用。
Selector被Dispatcher控制 。Dispatcher是一个单线程的类。与Selector是组合关系。Dispatcher类负责检索事件以及调遣处理所消耗的调度事件的EventHandler。通过循环,Dispatcher类调用Selector类的select方法来等待新事件。当新的事件进来时,select方法返回,同时先关联的channel通过调用selectedKeys方法被收回。
... while (isRunning) { // blocking call, to wait for new readiness events int eventCount = selector.select(); // get the events Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while(it.hasNext()) { SelectionKey key = it.next(); it.remove(); // readable event? if (key.isValid() && key.isReadable()) { eventHandler.onReadableEvent(key.channel()); } // writable event? if (key.isValid() && key.isWritable()) { key.interestOps(SelectionKey.OP_READ); eventHandler.onWriteableEvent(key.channel()); } ... } ... }
像准备写或者准备读这样的事件,Dispatcher会调用EventHandler来处理。EventHandler负责解码请求数据,处理所需的服务活动,编码相应数据。由于工作线程为等待新的请求而而浪费事件,可扩展性和吞吐量的瓶颈只取决于系统资源如CPU或内存。因为需要线程切换好同步,响应时间上会逊色于传统的每个线程负责一个连接的架构。而这种事件驱动方式的架构是用来减少同步,优化线程管理,因此,这方面的开销忽略不计。
未完待续