Reactor

Reactor

Web请求的两种体系结构

thread-based architecture(基于线程)

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

event-driven architecture(事件驱动)

  • 事件驱动体系结构是目前比较广泛使用的一种。这种方式会定义一系列的事件处理器来响应事件的发生,并且将服务端接受连接与对事件的处理分离。其中,事件是一种状态的改变。比如,tcp中socket的new incoming connection、ready for read、ready for write。

  • Reactor图示

reactor构成角色

Reactor结构

Handle

  • handle在linux中一般称为文件描述符,而在window称为句柄,两者的含义一样。本质上表示一种资源(比如说文件描述符,或是针对网络编程中的socket描述符),是由操作系统提供的;该资源用于表示一个个的事件,事件既可以来自于外部,也可以来自于内部;外部事件比如说客户端的连接请求,客户端发送过来的数据等;内部事件比如说操作系统产生的定时事件等。它本质上就是一个文件描述符,Handle是事件产生的发源地。比如一个网络socket、磁盘文件等。而发生在handle上的事件可以有connection、ready for read、ready for write等。

Synchronous Event Demultiplexer

  • 同步事件分离器,本质上是系统调用。用于等待事件的发生(事件可能是一个,也可能是多个)。调用方在调用它的时候会被阻塞,一直阻塞到同步事件分离器上有事件产生为止。对于Linux来说,同步事件分离器指的就是常用的I/O多路复用机制,比如说select、poll、epoll等。在Java NIO领域中,同步事件分离器对应的组件就是Selector;对应的阻塞方法就是select方法。

Event Handler

  • 事件处理器,其会定义一些回调方法或者称为钩子函数,当handle上有事件发生时,回调方法便会执行,一种事件处理机制。这些回调方法构成了与应用相关的对于某个事件的反馈机制。在Java NIO领域中并没有提供事件处理器机制让我们调用或去进行回调,是由我们自己编写代码完成的。Netty相比于Java NIO来说,在事件处理器这个角色上进行了一个升级,它为我们开发者提供了大量的回调方法,供我们在特定事件产生时实现相应的回调方法进行业务逻辑的处理,即,ChannelHandler。ChannelHandler中的方法对应的都是一个个事件的回调。

Concrete Event Handler

  • 具体的事件处理器,实现了Event Handler。在回调方法中会实现具体的业务逻辑。它本质上就是我们所编写的一个个的处理器实现。

Initiation Dispatcher

  • 初始分发器,也是reactor角色,它本身定义了一些规范,这些规范用于控制事件的调度方式,同时又提供了注册、删除与转发event handler的方法。Initiation Dispatcher会通过Synchronous Event Demultiplexer来等待事件的发生。一旦事件发生,Initiation Dispatcher首先会分离出每一个事件,然后调用事件处理器,最后调用相关的回调方法来处理这些事件。Netty中ChannelHandler里的一个个回调方法都是由bossGroup或workGroup中的某个EventLoop来调用的。

reactor处理流程

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

reactor分类

单reactor单线程

  • image-20210406113146187
  • 可靠性问题, 线程意外终止, 或者进入死循环, 会导致整个系统通信模块不可用, 不能接收和处理外部消息, 造成节点故障 ,无法发挥出多核CPU的性能

单reactor多线程

  • 单reactor多线程

  • reactor在单线程中运行,高并发场景下容易成为性能瓶颈

主从reactor多线程

  • img
  • Nginx和netty都使用了这种模型

拆包粘包

ReplayingDecoder


Reactor
https://x-leonidas.github.io/2022/02/01/11技术栈/Reactor/
作者
听风
发布于
2022年2月1日
更新于
2022年5月5日
许可协议