Reactor 模型

全宇宙最有名的、最高性能”的Web服务器Nginx,就是基于反应器模式的;如雷贯耳的Redis,作为最高性能的缓存服务器之一,也是基于反应器模式的;目前火得“一塌糊涂”、在开源项目中应用极为广泛的高性能通信中间件Netty,更是基于反应器模式的。反应器模式相当于高性能、高并发的一项非常重要的基础知识,只有掌握了它,才能真正掌握Nginx、Redis、Netty等这些大名鼎鼎的中间件技术。
Netty本身很抽象,大量应用了设计模式。学习像Netty这样的“精品中的精品”,肯定也是需要先从设计模式入手的。而Netty的整体架构,就是基于这个著名反应器模式。

【简介】

反应器模式由Reactor反应器线程、Handlers处理器两大角色组成:
(1)Reactor反应器线程的职责:负责响应IO事件,并且分发到Handlers处理器。
(2)Handlers处理器的职责:非阻塞的执行业务处理逻辑。
Doug Lea著名的文章《Scalable IO in Java》的链接地址贴出来:http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf,建议大家去阅读一下,提升自己的基础知识,开阔下眼界。
如果需要彻底了解反应器模式,还得从最原始的OIO编程开始讲起。

【while循环服务端编程】

在Java的OIO编程中,最初和最原始的网络服务器程序,是用一个while循环,不断地监听端口是否有新的连接。如果有,那么就调用一个处理函数来处理,这种方法的最大问题是:如果前一个网络连接的handle(socket)没有处理完,那么后面的连接请求没法被接收,于是后面的请求通通会被阻塞住,服务器的吞吐量就太低了。对于服务器来说,这是一个严重的问题。
为了解决这个严重的连接阻塞问题, 出现了一个极为经典模式:Connection Per Thread(一个线程处理一个连接)模式。
对于每一个新的网络连接都分配给一个线程。每个线程都独自处理自己负责的 输入和输出
当然,服务器的监听线程也是独立的,任何的socket连接的输入和输出处理,不会阻塞到后面新socket连接的监听和建立。
早期版本的Tomcat服务器,就是这样实现的。
Connection Per Thread模式(一个线程处理一个连接)的优点是:解决了前面的新连接被严重阻塞的问题,在一定程度上,极大地提高了服务器的吞吐量。
这里有个问题:如果一个线程同时负责处理多个socket连接的输入和输入,行不行呢?看上去,没有什么不可以。但是,实际上没有用。为什么?传统OIO编程中每一个socket的IO读写操作,都是阻塞的。在同一时刻,一个线程里只能处理一个socket,前一个socket被阻塞了,后面连接的IO操作是无法被并发执行的。所以,不论怎么处理,OIO中一个线程也只能是处理一个连接的IO操作。 Connection Per Thread模式的缺点是:对应于大量的连接,需要耗费大量的线程 资源,对线程资源要求太高。在系统中,线程是比较昂贵的系统资源。如果线程数太多,系统无法承受。而且,线程的反复创建、销毁、线程的切换也需要代价。因此,在高并发的应用场景下,多线程OIO的缺陷是致命的。

【Reactor基本原理啊】

在事件驱动模式中,当有事件触发时,事件源会将事件dispatch分发到handler处理器进行事件处理。反应器模式中的反应器角色,类似于事件驱动模式中的dispatcher事件分发器角色。
前面已经提到,在反应器模式中,有Reactor反应器和Handler处理器两个重要的组件:
(1)Reactor反应器:负责查询IO事件,当检测到一个IO事件,将其发送给相 应的Handler处理器去处理。这里的IO事件,就是NIO中选择器监控的通道IO事件。
(2)Handler处理器:与IO事件(或者选择键)绑定,负责IO事件的处理。完 成真正的连接建立、通道的读取、处理业务逻辑、负责将结果写出到通道等。

【单线程Reactor反应器模式】

什么是单线程版本的Reactor反应器模式呢?简单地说, Reactor反应器和 Handers处理器处于一个线程中执行。相当于IO查询事件和Handler处理由一个线程执行, 从性能来说,单线程的reactor没过多的提升,因为IO和CPU的速度还是严重不匹配
缺点:
单线程Reactor反应器模式,是基于Java的NIO实现的。 相对于传统的多线程 OIO,反应器模式不再需要启动成千上万条线程,效率自然是大大提升了。在单线程反应器模式中, Reactor反应器和Handler处理器,都执行在同一条线程 。这样, 带来了一个问题:当其中某个Handler阻塞时,会导致其他所有的Handler 都得不到执行。在这种场景下, 如果被阻塞的Handler不仅仅负责输入和输出处理的 业务,还包括负责连接监听的AcceptorHandler处理器。这个是非常严重的问题。 为什么?一旦AcceptorHandler处理器阻塞,会导致整个服务不能接收新的连 接,使得服务器变得不可用。因为这个缺陷,因此单线程反应器模型用得比较少。另外,目前的服务器都是多核的,单线程反应器模式模型不能充分利用多核资源。总之,在高性能服务器应用场景中,单线程反应器模式实际使用的很少。
代码实现:
其中,AcceptorHandler处理器的两大职责: 一是接受新连接,二是在为新连接创建一 个输入输出的Handler处理器,称之为IOHandler。

【多线程的Reactor反应器模式】

既然Reactor反应器和Handler处理器,挤在一个线程会造成非常严重的性能缺陷。那么,可以使用多线程,对基础的反应器模式进行改造和演进。
多线程池Reactor反应器的演进,分为两个方面:
(1)首先是 升级Handler处理器。既要使用多线程,又要尽可能的高效率,则 可以考虑使用线程池
(2)其次是 升级Reactor反应器。可以考虑引入多个Selector选择器,提升选择 大量通道的能力
总体来说,多线程池反应器的模式,大致如下:
(1) 将负责输入输出处理的IOHandler处理器的执行,放入独立的线程池中。 这样,业务处理线程与负责服务监听和IO事件查询的反应器线程相隔离,避免服务 器的连接监听受到阻塞
(2) 如果服务器为多核的CPU,可以将反应器线程拆分为多个子反应器 (SubReactor)线程;同时,引入多个选择器,每一个SubReactor子线程负责一个选 择器。这样,充分释放了系统资源的能力;也提高了反应器管理大量连接,提升选择大量通道的能力。
处理器:

【netty如何实现reactor模式】

一个IO事件从操作系统底层产生后,在Reactor反应器模式中的处理流程如图6-1所示。
整个流程大致分为4步,具体如下:
第1步:通道注册。IO源于通道(Channel)。IO是和通道(对应于底层连接而言)强相关的。一个IO事件,一定属于某个通道。但是,如果要查询通道的事件,首先要将通道注册到选择器。只需通道提前注册到Selector选择器即可,IO事件会被选择器查询到。
第2步:查询选择。在反应器模式中,一个反应器(或者SubReactor子反应器)会负责一个线程;不断地轮询,查询选择器中的IO事件(选择键)。
第3步:事件分发。如果查询到IO事件,则分发给与IO事件有绑定关系的Handler业务处理器。
第4步:完成真正的IO操作和业务处理,这一步由Handler业务处理器负责。以上4步,就是整个反应器模式的IO处理器流程。其中,第1步和第2步,其实是Java NIO的功能,反应器模式仅仅是利用了Java NIO的优势而已。

【Reactor反应器模式小结】

1.反应器模式和生产者消费者模式对比
相似之处: 在一定程度上,反应器模式有点类似生产者消费者模式。在生产者 消费者模式中,一个或多个生产者将事件加入到一个队列中,一个或多个消费者主 动地从这个队列中提取(Pull)事件来处理
不同之处在于: 反应器模式是基于查询的,没有专门的队列去缓冲存储IO事 件,查询到IO事件之后,反应器会根据不同IO选择键(事件)将其分发给对应的 Handler处理器来处理
2.反应器模式和观察者模式(Observer Pattern)对比
相似之处在于:在反应器模式中, 当查询到IO事件后,服务处理程序使用单路/ 多路分发(Dispatch)策略,同步地分发这些IO事件。观察者模式(Observer Pattern)也被称作发布/订阅模式,它定义了一种依赖关系,让多个观察者同时监听 某一个主题(Topic)。这个主题对象在状态发生变化时,会通知所有观察者,它们 能够执行相应的处理
不同之处在于:在反应器模式中,Handler处理器实例和IO事件(选择键)的订阅关系,基本上是一个事件绑定到一个Handler处理器;每一个IO事件(选择键)被查询后,反应器会将事件分发给所绑定的Handler处理器;而在观察者模式中,同一个时刻,同一个主题可以被订阅过的多个观察者处理。

反应器模式的优点和缺点:

优点如下:
·响应快, 虽然同一反应器线程本身是同步的,但不会被单个连接的同步IO所阻
·编程相对简单,最大程度避免了复杂的多线程同步,也避免了多线程的各个进程之间切换的开销;
·可扩展,可以方便地通过增加反应器线程的个数来充分利用CPU资源。
缺点如下:
·反应器模式增加了一定的复杂性,因而有一定的门槛,并且不易于调试。·反应器模式需要操作系统底层的IO多路复用的支持,如Linux中的epoll。如果操作系统的底层不支持IO多路复用,反应器模式不会有那么高效。
· 同一个Handler业务线程中,如果出现一个长时间的数据读写,会影响这个反 应器中其他通道的IO处理。例如在大文件传输时,IO操作就会影响其他客户端 (Client)的响应时间。因而对于这种操作,还需要进一步对反应器模式进行改进
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0x13

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值