【图解IO与Netty系列】Reactor模型

Reactor模型

Reactor模型简介

Reactor模型是服务器端用于处理高并发网络IO请求的编程模型,与传统的一请求一线程的同步式编程模型不同的是,Reactor模型是基于事件驱动的响应式编程模型,可以一个线程处理多个请求,并且是异步处理,在高并发场景下,性能大大的提升。

传统的同步式编程模型如下:

服务端接收到请求后,从线程池中拿出一个线程(比如Tomcat里的线程池),经过Controller、Service、Dao的一顿处理,最后返回响应结果给客户端。这种同步处理请求的方式效率并不高,可以应对一些并发量不高的场景。

基于事件驱动的响应式编程模型如下:

  1. 服务端启动时,会创建Reactor反应器,然后会向Reactor注册基本的事件类型与对应的Handler(比如网络编程时的连接就绪事件与Acceptor)
  2. 当服务端接收到客户端的请求时,服务端的Reactor就有事件就绪,Reactor会获取到就绪的事件,在高并发场景下,Reactor有可能获取到一批就绪的事件
  3. Reactor进事件分发,把事件分派给与之绑定的Handler中,Handler对事件的处理可以在当前线程中也可以在线程池中,当然在线程池中处理性能会更高
  4. Handler处理完毕后,如果后续还有其他处理步骤,则可以继续注册新的事件与对应的Handler到Reactor中;如果没有后续,则可以返回响应结果给客户端,返回响应结果这个动作可作为单独的一个事件,由对应的Handler进行处理,那么也可以继续注册到Reactor中。

Reactor其实就是一个线程,可以看到它就在一个死循环中进行事件监听以及事件分派,这就是事件循环。

Reactor模型底层使用了IO多路复用,通过对IO多路复用机制的合理利用,使得服务器端达到高效的处理网络IO请求的目的。我们可以使用Java提供的NIO来实现Java版本的Reactor模型。

三类事件与三类角色

Reactor模型抽象了三类事件和三类角色,它们是Reactor模型的核心组成部分。三类事件是:连接就绪事件,读就绪事件、写就绪事件。三类角色是:Reactor、Acceptor、Handler。

首先我们来了解一下三类事件。

  • 连接就绪事件:客户端向服务端发起连接的时候,对应的Channel就有连接就绪事件发生。
  • 读就绪事件:当客户端向服务器端发送数据时,对应的Channel就有读就绪事件发生。
  • 写就绪事件:当服务器处理完客户端发送的数据,需要返回结果时,可以向Selector注册一个写就绪事件并与对应的Channel关联,那么对应Channel就有写就绪事件发生。

我们再来了解一下三类角色。

Reactor是相当于是一个事件分派器,Reactor专门负责监听事件的发生,并把发生的事件交给对应的处理器处理,这里的处理器指的就是Acceptor或Handler。Reactor是一个线程,它通过Selector注册并监听多个Channel,如果监听到有事件发生,判断是连接就绪事件,会交给Acceptor处理,如果发生的事件是读就绪事件或写就绪事件,会交给Handler处理。

如果是连接就绪事件,Reactor会将其分派给Acceptor处理,Acceptor会调用accept()方法获取到连接对应的SocketChannel,然后会将其设置为非阻塞,注册到Reactor的Selector中,设置关注的事件为读就绪事件。

如果是读就绪事件,那么Reactor会将其分派给与其绑定的Handler处理,该Handler会经过read、decode、compute、encode、send五个步骤的处理。

  1. read:读取Channel中的数据
  2. decode:对读到的数据进行解码
  3. compute:解码后的数据进行相应处理
  4. encode:对处理后的结果进行编码
  5. send:编码后的数据发送给客户端。

之所以要进行decode和encode,是因为数据在网络上是以二进制的形式传输的,因此服务端接收到后要对二进制字节码进行解码操作,然后才能对解码后的数据进行处理,处理完的数据要发送到网络,也要编码成二进制的格式。

其中,send操作可以立刻发送数据写出到Channel,也可以注册一个写就绪事件到Selector,这就相当于进行异步发送。

Reactor模型整体流程

  1. 首先,一开始我们只把ServerSocketChannel以及连接事件处理器Acceptor注册到Reactor中,Reactor会把ServerSocketChannel注册到Selector中,并设置关注连接就绪事件
  2. 一旦客户端发起连接,ServerSocketChannel的连接就绪事件就绪,Reactor会将其分派给Acceptor处理,Acceptor会获取到连接对应的SocketChannel,并将其与对应的处理器Handler注册到Reactor,Reactor会将其注册到Selector中。
  3. 随后客户端向服务端发送数据,Reactor监听到对应的SocketChannel有读就绪事件发生,会将其分派给与其绑定的Handler进行处理。
  4. Handler被分派到读就绪事件时,会经过read、decode、compute、encode、send五个步骤的处理。
  5. 服务端要把处理结果返回给客户端,会向Reactor注册一个对应Channel的写就绪事件,Reactor监听到写就绪事件,会分派给与该Channel绑定的Handler处理,Handler把返回结果发送出去。

各种Reactor模型

Reactor编程模型不是只有单一的一种编程模型,它有单Reactor单线程模型、单Reactor多线程模型、主从Reactor模型等多种模型。

单Reactor单线程模型

单Reactor单线程模型是最简单的模型,当然性能也是最低的。单Reactor模型只有一个Reactor,这个Reactor即负责处理连接建立,也负责数据读写和计算等处理。并且由于是单线程模型,所以数据读取后的计算处理,也是在当前线程中完成。

这种单Reactor单线程模型虽然性能比其他的Reactor模型低,但是优点是比较的简单,没有了多线程就意味着没有了"多线程翻车"的一些情况出现。值得一提的是,Redis的事件驱动框架就是单Reactor单线程模型

但是由于连接建立与IO处理都在一个Reactor线程中进行,因此在高并发场景下,该Reactor线程的压力会非常大,特别是在数据计算还比较复杂的场景,单线程的Reactor模型有可能支撑不住。之所以Redis使用单Reactor单线程模型还能支撑高并发读写的场景,其中一个原因是因为Redis内部不涉及太复杂的数据计算。

单Reactor多线程模型

单Reactor多线程模型是在单Reactor模型的基础上增加了线程池,可以把decode、compute、encode等需要计算的操作提交到线程池执行,而Reactor线程则专注于连接建立与IO的处理(也就是read和send)。

把涉及到计算的处理抽到了线程池中处理,可以在一定程度上缓解Reactor线程的压力。但是由于还是单Reactor模型,IO处理依然在该Reactor线程中进行,高并发场景下,可能会由于大量的IO请求需要处理而导致连接建立的处理受到影响,该Reactor线程可能无法及时响应客户端连接建立的请求。

主从Reactor模型

主从Reactor模型在单Reactor多线程模型基础上做了改进,把IO处理分离到了子Reactor中,主Reactor只专注于连接请求的处理,主Reactor一般只有一个(也可有多个),而子Reactor一般有多个。当主Reactor上有连接就绪事件发生时,通过Acceptor获取到连接对应的SocketChannel,然后把该SocketChannel注册到子Reactor中,由子Reactor监听该Channel的读就绪事件并处理。

由于连接建立与IO处理分离到了不同的Reactor,当有大量并发的IO请求需要处理时,也不会影响到客户端建立连接的请求。

相关推荐
ZLRRLZ11 分钟前
【ProtoBuffer】protobuffer的安装与使用
服务器·网络
这周也會开心14 分钟前
云服务器安装JDK、Tomcat、MySQL
java·服务器·tomcat
hrrrrb1 小时前
【Spring Security】Spring Security 概念
java·数据库·spring
小信丶1 小时前
Spring 中解决 “Could not autowire. There is more than one bean of type“ 错误
java·spring
周杰伦_Jay2 小时前
【Java虚拟机(JVM)全面解析】从原理到面试实战、JVM故障处理、类加载、内存区域、垃圾回收
java·jvm
摇滚侠3 小时前
Spring Boot 3零基础教程,IOC容器中组件的注册,笔记08
spring boot·笔记·后端
像素之间3 小时前
HTTP之content-disposition
网络·网络协议·http
2501_915909065 小时前
tcpdump 抓包数据分析实战,命令、过滤、常见故障定位与真机补充流程
网络·测试工具·ios·小程序·uni-app·iphone·tcpdump
程序员小凯6 小时前
Spring Boot测试框架详解
java·spring boot·后端
路由侠内网穿透6 小时前
本地部署开源持续集成和持续部署系统 Woodpecker CI 并实现外部访问
服务器·网络·windows·ci/cd·开源