当前位置: 首页 > 图灵资讯 > 技术篇> 高性能网络通信模型——Reactor 和 Proactor

高性能网络通信模型——Reactor 和 Proactor

来源:图灵教育
时间:2023-09-03 16:59:29

原来 8 图片,可以学废 Reactor 和 Proactor (qq.com)

高并发编程-Reactor模式和Proactor模式 (qq.com)

image-20230903120136559

Reactor模型

Reactor,翻译成反应器是一种被动的感觉,可以理解为Reactor模型在收到客户端事件后会根据事件类型调用相应的代码进行处理。Reactor模型又称Dispatcher模型,底层为I/O多路复用组合线程池。

Reactor模型的核心思想可以概括为两个“三种”,主要用于服务器端处理高并发网络IO请求。:

  • 三种事件——连接事件、阅读事件、写事件
  • 三种角色——reactor、acceptor、handler
事件
  • 客户端将连接请求发送到服务器端,对应于服务器的连接事件
  • 连接建立后,客户端向服务器端发送写作请求,服务器端收到请求,需要从请求中读取内容,这与服务器端读取事件相对应
  • 处理后,服务器将结果值返回给客户端,这与服务器的写作事件相对应

image-20230903150731770

角色

以上描述了Reactor事件,每次都需要有专门的负责人。在Reactor模型中,该负责人是角色,说明如下:

  • 连接事件由acceptor处理,只负责接收连接;acceptor接收连接后,将创建handler处理后续读写事件
  • 读写事件由handler处理,处理后响应客户端
  • 在连接事件和读写事件同时发生的高并发场景中,Reactor角色需要专门监控和分配事件:连接事件给acceptor,读写事件给handler。
Reactor线程模型

Reactor 线程模型有「单 Reactor 单线程模型」、「单 Reactor 多线程模型」、「多 Reactor 多线程模型」 三种。

其中,「多 Reactor 单进程 / 线程」与实现方案相比「单 Reactor 单进程 / 线程」该方案不仅复杂,而且没有性能优势,因此在实践中没有应用。

至于是线程还是过程,Java 线程通常用于语言

1 单Reactor单线程模型

单 Reactor 单线程模型,易于理解:在一个线程中处理接受请求、业务处理和响应请求。

图片

工作原理:

  1. Reactor通过监控select函数监控事件,通过dispatch将事件分发给acceptor或handler;
  2. 如果客户端的连接事件被监控,则分发给acceptor处理,acceptor通过accept接收连接,并创建一个handler事件来处理后续事件;
  3. 如果不是连接建立事件,reactor将调用连接对应的handler(在步骤2中创建的handler)进行响应
  4. handler通过:read -> 业务处理 -> 完成send流程的完整业务流程

优缺点:

  • 优点是简单,没有线程竞争,
  • 缺点是不能充分利用和发挥多核CPU的性能。当业务耗时较长时间时,很容易造成阻塞

案例:

  • Redis 6.0以下版本使用「单 Reactor 单线程模型」,因为 Redis使用内存,CPU不是性能瓶颈,所以单个 Reactor 可支持单线程模型 Redis 高性能的单机服务
  • Netty4 单个参数可以通过参数配置使用 Reactor 单线程模型;
2 单Reactor多线程模型

鉴于单 Reactor 单线程模式不能充分利用和发挥多核 CPU 因此,单一的性能诞生了 Reactor 多线程模型。

图片

工作原理

  1. 主线程中,Reactor 对象通过 select 监控事件,收到事件后通过 dispatch 分发给 Acceptor 或 Handler;
  2. 如果监听到 client 将连接事件分发给 Acceptor 处理,Acceptor 通过 accept 接收连接并创建一个 Handler 处理各种连接后续事件;
  3. 若不是连接建立事件,则 Reactor 相应的连接将被调用 Handler(步骤2创建 Handler)响应。注意,这个模型 Handler 只负责响应事件,不处理业务;
  4. Handler 通过 read 读取数据后,它将被发送 Processor 业务处理;
  5. Processor 真正的业务处理将在独立的子线程中完成,然后将响应结果发送到主线程 Handler 处理;Handler 收到响应后通过 send 返回响应结果 client;

优点

使用线程池处理业务逻辑,可以充分利用更多 CPU 的处理能力

缺点

  1. 多线程数据共享和访问更为复杂。例如,在子线程完成业务处理后,将结果传递给主线程 Reactor 发送涉及共享数据的互斥和保护机制;
  2. 虽然引入了多线程处理的业务逻辑,但事件的监控和响应仍然需要 Reactor 因此,瞬时高并发可能会导致 Reactor 性能瓶颈;

案例

  • Netty4 单个参数可以通过参数配置使用 Reactor 多线程模型;
3 多Reactor多线程模型

单 Reactor 多线程模型的性能瓶颈在于单个单线程模型 Reactor 处理能力,所以我们自然会想:能不能增加多个? Reactor来提高性能?所以,更多 Reactor 多线程模型应孕而生。

图片

工作原理

  1. 父线程中 mainReactor 对象通过 select 监控连接建立事件,收到事件后通过 Acceptor 接收,将新的连接分配到子线程;
  2. 子线程的 subReactor 把 mainReactor 将分配的连接添加到连接队列中进行监控,并创建一个 Handler 处理各种连接事件;
  3. 当发生新事件时,subReactor 相应的连接将被调用 Handler(步骤2创建 Handler)响应;
  4. Handler 通过:read-> 业务处理 ->send 完成完整的业务流程;

优点

  • 父线程和子线程的职责明确,父线程只负责接收新连接,子线程负责完成后续业务处理;
  • 父线程与子线程交互简单,父线程只需将新的连接传输到子线程,子线程不需要返回数据;

案例

  • Nginx 采用的是多 Reactor 多过程模型,但方案和标准较多 Reactor 多过程有差异;

  • 开源软件 Memcache 采用的是多 Reactor 多线程模型;

  • Netty4 可以通过参数参数配置使用多个参数参数 Reactor 多线程模型;

到此, 分析了Reactor模型,需要注意的是:上面描述的 Reactor 三种线程模型,也可以通过进程的方式部署,在逻辑处理上可能与线程不同。

接下来再分析一下 Reactor模型非常相似 Proactor 模型

Proactor 模型

Proactor,中文翻译成“前摄像头”。乍一看,这个翻译还是挺傻的,个人觉得“主动器”更符合。 Proactor 模型的初衷。Proactor 可以理解为“当有连接、读写等IO事件时,操作系统内核在处理事件后主动通知我们的程序代码”。

可以理解为actor Pro Plus Ultra

图片

工作原理

  • Proactor Initiator 负责创建 Proactor 和 Handler,并将 Proactor 和 Handler 都通过 Asynchronous Operation Processor 内核注册;
  • Asynchronous Operation Processor 负责处理登记请求并完成登记请求 I/O 操作;
  • Asynchronous Operation Processor 完成 I/O 操作后通知 Proactor;
  • Proactor 根据不同类型的事件回调不同的事件 Handler 业务处理;
  • Handler 完成业务处理,Handler 也可以注册新的 Handler 内核过程;

优缺点

  • Proactor 处理高耗时 IO 性能高于时间 Reactor,但是对于低耗时 IO 执行效率提高不明显;
  • Proactor 异步性使其并发处理能力强于 Reactor;
  • Proactor 逻辑复杂,编码成本更高 Reactor 要高很多;
  • Proactor 异步高度依赖于操作系统对异步的支持。如果操作系统不支持异步,Proactor 性能不如 Reactor;

案例

  • Nettty5, 它是采用 AIO,它的网络通信模型是 Proactor,但是这个版本之所以不再维护,主要是因为 Linux 目前对异步的支持不完善,导致异步的支持不完善 Netty5 成本高,性能相对较高 Netty4 不但没有改善,甚至没有减少。
总结
  • Reactor 是同步非阻塞网络模型,Proactor 异步非阻塞网络模型;

  • Reactor 是 I/O 多路复用与线程池的完美结合;

  • Reactor模型看似高深,实际上是生活中许多真实案例的写照,如:

    1. 夜市老板单人炒粉模式,从点菜、出餐、结算都是老板一个人完成的,这是相应的 单 Reactor单线程模型;
    2. 医院叫号看病对应。 单 Reactor多线程模型,一个叫号机负责叫号,多个医生负责接待病人;
    3. 大型餐饮用餐对应 多 在Reactor多线程模型中,一个接待员负责接送客人,多个服务员,每个服务员负责几桌客人,然后专门的端菜人员负责给客人端菜,比如海底捞;
  • Reactor思维也经常用于日常开发,最常用的是单线程处理。当并发量较大时,引入线程池,细分业务,处理特殊的线程,以便与之和解 Reactor 模型的演变类似于同工之妙;

  • Proactor 异步主要用于处理 IO 事件(比如叫外卖,下单付款后不需要注意,直接处理自己的事情。外卖完成后,外卖兄弟会主动把外卖送给你),但目前 Linux 对 AIO支持不友好,使用该模型 Netty5 最后也死了;