02-Reactor模式

Reactor模式

一、两种体系结构

  • 处理web请求通常有两种体系结构,非别是基于线程(thread-based architecture)和事件驱动(event-driven architecture)。

1.1 基于线程

  • 基于线程的体系结构通常会使用多线程来处理客户端的请求,每当接收到一个请求,便开启一个独立的线程来处理。这种方式虽然是直观的,但是仅适用于并发访问量不大的场景,因为线程需要占用一定的内存资源,且操作系统在线程之间的切换也需要一定的开销,当线程数过多时显然会降低web服务器的性能。并且,当线程在处理I/O操作,在等待输入的这段时间线程处于空闲的状态,同样也会造成cpu资源的浪费。
优点:
1.方式简单,直观
2.使用于并发量不大的场景

缺点:
1.线程占用资源,切换开销也很大,不适用与高并发场景
2.浪费IO;线程处理IO期间,Cpu资源会浪费

1.2 基于事件

  • 事件驱动体系结构是目前比较广泛使用的一种。该方式会定义一系列的事件处理器来响应事件的发生,并且将服务端接受连接与对事件的处理分离。其中事件是一种状态的改变。比如,tcp中socket的new incoming connection、ready for read、ready for write。
事件驱动模型中,将连接、读数据、写数据都抽象为不同的事件类型,不同的事件类型有对应的事件处理器。
服务端将对事件的监听和处理两个步骤分离,由此不让事件的处理阻塞对事件的监听。

二、Reactor

2.1 概念

  • Reactor设计模式是事件驱动的一种实现方式,常用于处理多个客户端并发的向服务端请求服务的场景。Reactor会解耦并发请求并分发给对应的事件处理器来处理。许多流行的开源框架都用到了Reactor模式,如:netty、node.js、java的nio等。
1.一种基于事件驱动的设计模式
2.专门为处理多客户端并发请求
3.用非阻塞模块来接收请求、然后派发到对应的模块进行处理。

handle:句柄或者文件描述符,一般是Socket,注册到事件分离器
事件分离器:等待新事件,有新事件就通知事件分发器(注册事件)
事件分发器:管理事件,并将事件分发给事件处理器(回调事件处理器的回调分发)
事件处理器:处理不同的事件,由事件分发器调用

2.2 Reactor模型的组成部分

2.2.1 Handle
  • handle在linux中一般称为文件描述符,而在window称为句柄,两者的含义一样。handle是事件的发源地,比如一个网络socket、磁盘文件等。而发生在handle上的事件可以有connection、ready for read、ready for write等。
2.2.2 Synchronous Event Demultiplexer
  • 同步事件分离器,本质上是系统调用。比如linux中的select、poll、epoll等。方法在被调用时会一直阻塞,直到产生事件,比如,select方法会一直阻塞直到handle上有事件发生时才会返回。我想因为这几个方法都会阻塞直到产生事件,因此才叫做同步事件处理器。在Java Nio中同步事件分离器对应的组件就是Selector,对应的阻塞方法就是select方法。(NIO是一种同步非阻塞的I/O模型,也是I/O多路复用的基础。)
2.2.3 Event Handler
  • 事件处理器,其会定义一些回调方法或者称为钩子函数,当handle上有事件发生时,回调方法便会执行,一种事件处理机制。
2.2.4 Concrete Event Handler
  • 具体的事件处理器,实现了Event Handler。在回调方法中会实现具体的业务逻辑。
2.2.5 Initiation Dispatcher
  • 初始分发器,也是reactor角色,提供了注册、删除与转发eventhandler的方法。当同步事件分离器检测到handle上有事件发生时,便会通知初始分发器调用特定的event handler的回调方法。

  • 它本身定义了一些规范,这些规范用于控制事件的调度方式,同时又提供了应用进行事件处理器的注册、删除等设施。 初始分发器通过同步事件分离器来等待事件的发生。一旦事件发生,初始分发器会分离出事件然后调用事件处理器,最后调用相关的回调方法来处理这些事件。Netty中ChannelHandler里的一个个回调方法都是由bossGroup或workGroup中的某个EventLoop来调用的。

2.3 Reactor处理流程

    1. 当应用向Initiation Dispatcher注册Concrete Event Handler时,应用会标识出该事件处理器希望Initiation Dispatcher在某种类型的事件发生发生时向其通知,事件与handle关联
    1. Initiation Dispatcher要求注册在其上面的Concrete Event Handler传递内部关联的handle,该handle会向操作系统标识
    1. 当所有的Concrete Event Handler都注册到 Initiation Dispatcher上后,应用会调用handle_events方法来启动Initiation Dispatcher的事件循环,这时Initiation Dispatcher会将每个Concrete Event Handler关联的handle合并,并使用Synchronous Event Demultiplexer来等待这些handle上事件的发生
    1. 当与某个事件源对应的handle变为ready时,Synchronous Event Demultiplexer便会通知 Initiation Dispatcher。比如tcp的socket变为ready for reading
    1. Initiation Dispatcher会触发事件处理器的回调方法。当事件发生时, Initiation Dispatcher会将被一个“key”(表示一个激活的handle)定位和分发给特定的Event Handler的回调方法
    1. Initiation Dispatcher调用特定的Concrete Event Handler的回调方法来响应其关联的handle上发生的事件

三、Reactor的几种模式

3.1 Reactor单线程(使用少)

  • 每个客户端发起连接请求都会交给acceptor,acceptor根据事件类型交给线程handler处理,注意acceptor 处理和 handler 处理都在一个线程中处理,所以其中某个 handler 阻塞时, 会导致其他所有的 client 的 handler 都得不到执行, 并且更严重的是, handler 的阻塞也会导致整个服务不能接收新的 client 请求(因为 acceptor 也被阻塞了). 因为有这么多的缺陷, 因此单线程Reactor 模型用的比较少.

3.2 Reactor多线程模式

  • 有专门一个线程, 即 Acceptor 线程用于监听客户端的TCP连接请求.
  • 客户端连接的 IO 操作都是由一个特定的 NIO 线程池负责. 每个客户端连接都与一个特定的 NIO 线程绑定, 因此在这个客户端连接中的所有 IO 操作都是在同一个线程中完成的.
  • 客户端连接有很多, 但是 NIO 线程数是比较少的, 因此一个 NIO 线程可以同时绑定到多个客户端连接中.
  • 缺点:如果我们的服务器需要同时处理大量的客户端连接请求或我们需要在客户端连接时, 进行一些权限的检查, 那么单线程的 Acceptor 很有可能就处理不过来, 造成了大量的客户端不能连接到服务器.

3.3 Reactor主从模式

  • 主从模式中分工如下
mainReactor: 监听ServerSocketChannel 、建立与 SocketChannel 的连接、将完成建立连接之后的Socket 交给subReactor
subReactor: 监听SocketChannel的 I/O事件,完成编解码、相应的业务处理(默认为CPU个数)
  • PS : Netty中实现了单线程模式和主从模式;

四、Reactor实现基础?

  • Reactor模型的IO多路复用中的一种,而在不同的平台,实现IO多路复用的关键是通过一个系统调用来同时阻塞多个IO操作。比如select、poll、epoll,这些是实现IO多路复用的系统基础,因此也是实现Reactor模型的基础,比如在Redis中,它的服务端的线程模型就是IO多路复用,redis内部封装了底层的select、epoll等系统调用方法。

五、小结

5.1 Linux IO模型?

  • Linux下面有五种IO模型,其中四种同步IO,一种异步IO。同步IO中有一种同步阻塞,其余的都是同步非阻塞:同步非阻塞、IO多路复用和信号驱动IO。

5.2 Reactor?

  • Reactor是一种基于事件驱动的设计模式。它使用同步事件处理器等待事件,并通过分发器将实践交给不同的事件处理器处理,,常用于处理多个客户端并发的向服务端请求服务的场景。
  • Reactor核心是将等待事件和事件的处理分离,不需要一个线程来处理一个连接。

5.3 Reactor的应用?

  • Reactor只是一种设计模式,他在不同的语言和通信框架中有不同的实现,比如Netty、node.js、Java的NIO。

5.4 Reactor和IO模型的关系?

  • Reactor是IO多路复用中的一种,IO多路复用除了Reactor,还有其他的。

5.5 Netty和Java NIO的区别?

  • Netty是基于Java NIO来实现的。不管是Netty和Java NIO,都算是Reactor模型的一直实现,因此他们都对应IO模型中的IO多路复用模型。
  • Java NIO提供了Java的非阻塞IO的基本API,Netty是基于Java NIO实现的一个客户端服务端框架,简化了编程,屏蔽了细节,简化了网络编程的开发。

5.6 Reactor或者IO多路复用实现的底层支持?

  • select、poll、epoll

六、参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值