高性能IO之Reactor模式(转载)

讲到高性能IO绕不开Reactor模式,它是大多数IO相关组件如Netty、Redis在使用的IO模式,为何须要这种模式,它是如何设计来解决高性能并发的呢?html

最最原始的网络编程思路就是服务器用一个while循环,不断监听端口是否有新的套接字链接,若是有,那么就调用一个处理函数处理,相似:while(true){ socket = accept(); handle(socket) } 这种方法的最大问题是没法并发,效率过低,若是当前的请求没有处理完,那么后面的请求只能被阻塞,服务器的吞吐量过低。以后,想到了使用多线程,也就是很经典的connection per thread,每个链接用一个线程处理,相似:while(true){ socket = accept(); new thread(socket); } tomcat服务器的早期版本确实是这样实现的。多线程的方式确实必定程度上极大地提升了服务器的吞吐量,由于以前的请求在read阻塞之后,不会影响到后续的请求,由于他们在不一样的线程中。这也是为何一般会讲“一个线程只能对应一个socket”的缘由。最开始对这句话很不理解,线程中建立多个socket不行吗?语法上确实能够,可是实际上没有用,每个socket都是阻塞的,因此在一个线程里只能处理一个socket,就算accept了多个也没用,前一个socket被阻塞了,后面的是没法被执行到的。缺点在于资源要求过高,系统中建立线程是须要比较高的系统资源的,若是链接数过高,系统没法承受,并且,线程的反复建立-销毁也须要代价。线程池自己能够缓解线程建立-销毁的代价,这样优化确实会好不少,不过仍是存在一些问题的,就是线程的粒度太大。每个线程把一次交互的事情所有作了,包括读取和返回,甚至链接,表面上彷佛链接不在线程里,可是若是线程不够,有了新的链接,也没法获得处理,因此,目前的方案线程里能够当作要作三件事,链接,读取和写入。线程同步的粒度太大了,限制了吞吐量。应该把一次链接的操做分为更细的粒度或者过程,这些更细的粒度是更小的线程。整个线程池的数目会翻倍,可是线程更简单,任务更加单一。这其实就是Reactor出现的缘由,在Reactor中,这些被拆分的小线程或者子过程对应的是handler,每一种handler会出处理一种event。这里会有一个全局的管理者selector,咱们须要把channel注册感兴趣的事件,那么这个selector就会不断在channel上检测是否有该类型的事件发生,若是没有,那么主线程就会被阻塞,不然就会调用相应的事件处理函数即handler来处理。典型的事件有链接,读取和写入,固然咱们就须要为这些事件分别提供处理器,每个处理器能够采用线程的方式实现。一个链接来了,显示被读取线程或者handler处理了,而后再执行写入,那么以前的读取就能够被后面的请求复用,吞吐量就提升了。
几乎全部的网络链接都会通过读请求内容——》解码——》计算处理——》编码回复——》回复的过程,Reactor模式的的演化过程以下:
 
这种模型因为IO在阻塞时会一直等待,所以在用户负载增长时,性能降低的很是快。
server致使阻塞的缘由:
一、serversocket的accept方法,阻塞等待client链接,直到client链接成功。
二、线程从socket inputstream读入数据,会进入阻塞状态,直到所有数据读完。
三、线程向socket outputstream写入数据,会阻塞直到所有数据写完。
改进:采用基于事件驱动的设计,当有事件触发时,才会调用处理器进行数据处理。
 
Reactor:负责响应IO事件,当检测到一个新的事件,将其发送给相应的Handler去处理。
Handler:负责处理非阻塞的行为,标识系统管理的资源;同时将handler与事件绑定。
Reactor为单个线程,须要处理accept链接,同时发送请求处处理器中。
因为只有单个线程,因此处理器中的业务须要可以快速处理完。
改进:使用多线程处理业务逻辑。
 
将处理器的执行放入线程池,多线程进行业务处理。但Reactor仍为单个线程。
继续改进:对于多个CPU的机器,为充分利用系统资源,将Reactor拆分为两部分。
Using Multiple Reactors
Using Multiple Reactors
Using Multiple Reactors
mainReactor负责监听链接,accept链接给subReactor处理,为何要单独分一个Reactor来处理监听呢?由于像TCP这样须要通过3次握手才能创建链接,这个创建链接的过程也是要耗时间和资源的,单独分一个Reactor来处理,能够提升性能。
Reactor模式是什么,有哪些优缺点?
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。若是用图来表达:
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。若是用图来表达:从结构上,这有点相似生产者消费者模式,即有一个或多个生产者将事件放入一个Queue中,而一个或多个消费者主动的从这个Queue中Poll事件来处理;而Reactor模式则并无Queue来作缓冲,每当一个Event输入到Service Handler以后,该Service Handler会主动的根据不一样的Event类型将其分发给对应的Request Handler来处理。
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。若是用图来表达:从结构上,这有点相似生产者消费者模式,即有一个或多个生产者将事件放入一个Queue中,而一个或多个消费者主动的从这个Queue中Poll事件来处理;而Reactor模式则并无Queue来作缓冲,每当一个Event输入到Service Handler以后,该Service Handler会主动的根据不一样的Event类型将其分发给对应的Request Handler来处理。
从结构上,这有点相似生产者消费者模式,即有一个或多个生产者将事件放入一个Queue中,而一个或多个消费者主动的从这个Queue中Poll事件来处理;而Reactor模式则并无Queue来作缓冲,每当一个Event输入到Service Handler以后,该Service Handler会主动的根据不一样的Event类型将其分发给对应的Request Handler来处理。
在解决了什么是Reactor模式后,咱们来看看Reactor模式是由什么模块构成。图是一种比较简洁形象的表现方式,于是先上一张图来表达各个模块的名称和他们之间的关系:
在解决了什么是Reactor模式后,咱们来看看Reactor模式是由什么模块构成。图是一种比较简洁形象的表现方式,于是先上一张图来表达各个模块的名称和他们之间的关系: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模式是由什么模块构成。图是一种比较简洁形象的表现方式,于是先上一张图来表达各个模块的名称和他们之间的关系: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接口,实现特定事件处理逻辑。
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接口,实现特定事件处理逻辑。
优势
1)响应快,没必要为单个同步时间所阻塞,虽然Reactor自己依然是同步的; 2)编程相对简单,能够最大程度的避免复杂的多线程及同步问题,而且避免了多线程/进程的切换开销; 3)可扩展性,能够方便的经过增长Reactor实例个数来充分利用CPU资源; 4)可复用性,reactor框架自己与具体事件处理逻辑无关,具备很高的复用性;缺点
1)相比传统的简单模型,Reactor增长了必定的复杂性,于是有必定的门槛,而且不易于调试。 2)Reactor模式须要底层的Synchronous Event Demultiplexer支持,好比Java中的Selector支持,操做系统的select系统调用支持,若是要本身实现Synchronous Event Demultiplexer可能不会有那么高效。 3) Reactor模式在IO读写数据时仍是在同一个线程中实现的,即便使用多个Reactor机制的状况下,那些共享一个Reactor的Channel若是出现一个长时间的数据读写,会影响这个Reactor中其余Channel的相应时间,好比在大文件传输时,IO操做就会影响其余Client的相应时间,于是对这种操做,使用传统的Thread-Per-Connection或许是一个更好的选择,或则此时使用Proactor模式。
 
原文连接:https://www.cnblogs.com/doit8791/p/7461479.html
相关文章
相关标签/搜索