Reactor模式Proactor模式

2024-05-28 02:52
文章标签 模式 reactor proactor

本文主要是介绍Reactor模式Proactor模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.Reactor/Dispatcher模式

1.1 概述

Reactor模式下,服务端的构成为Reactor + 处理资源池。其中,Reactor负责监听和分发事件,而处理资源池则负责处理事件。
该模式下的组合方案有下面几种(第三种几乎没有被实际应用):

  1. 1 * Reactor + 1 * Worker。
  2. 1 * Reactor + n * Worker。
  3. n * Reactor + 1 * Worker
  4. n * Reactor + n * Worker。

注:Worker是指负责处理事件的工作进程/线程。

n * Reactor + 1 * Worker 没有应用的原因(类比Redis为什么始终坚持单线程处理(执行)指令的原因):

  1. 复杂且没有性能优势。
    1. 复杂:多个Reactor去接收用户请求,这就需要处理好线程并发问题。
    2. 没有性能优势:多线程并发,如果是在单核上,可能会面临频繁的线程上下文切换,开销较大。其次,由于我们基本上是在内存中进行请求接收的,因此主要的瓶颈不在于线程数量而在于网络时延&带宽。
  2. 多个reactor去负责接待请求,而真正服务请求的时候确实串行的,你不觉得?。。。

1.2 实现方式

1.2.1 1 * Reactor + 1 * Worker

1.2.1.1 概述


该模式下的三种角色:

  • reactor:负责监听和分发事件。
  • acceptor:获取连接。
  • handler:处理事件。

执行流程

  1. reactor通过select系统调用持续监听IO事件,若监听到有事件发生,则根据事件类型进行分情况处理:
    1. 若为连接事件:则将该事件**分发(dispatch)**给acceptor处理,acceptor在收到该事件后,会通过accept系统调用新建一个连接并同时创建一个handler来处理后续的事件。
    2. 若不是连接事件:则交由handler进行事件处理。
1.2.1.2 评估
  • 该方案不适用于计算密集型场景,仅适用于业务耗时短的场景。
  • 由于全程采用单进程/线程监听&处理任务,因此无法充分利用多核CPU的性能。而且,一旦事件消费的过程中,某个事件的消费耗时特别长,它将影响到后续事件的响应,一般体现在延迟的增加方面。

C语言编写的服务端程序,其模式为1 * Reactor + 1 * 进程,而Java的则是1 * Reactor + 1 * 线程(JVM是一个进程,你所写好的Java程序是其中的一个线程)。
Redis 6.0- 采用的是1 * Reactor + 1 * 进程

1.2.2 1 * Reactor + n * Worker

1.2.2.1 概述


与前面不同的是:
handler不在负责事件的处理,而是负责数据的接收与发送。
handler在通过read系统调用拿到数据后,会将其转交给子线程中的processor进行处理,然后processor处理完成后,再将处理好的数据返回给handlerhandler再通过send系统调用将结果发回客户端。

1.2.2.2 评估
  • 该方案能够充分利用多核CPU的性能。
  • 由于该方案采用多进程/线程来进行事件的处理,因此需要注意在多线程环境下的共享数据的安全问题,而这实现起来,因此该方案较前者复杂一些。
  • 需要注意在高并发环境下,1个reactor可能会成为性能瓶颈的隐患。

1.2.3 n * Reactor + n * Worker

1.2.3.1 概述


与前面不同的是:
handler又再次负责事件的处理了。
对于新的连接事件,将首先分发给acceptor,然后acceptor创建出一个连接来,并将其分发给众多子线程中的其中一个线程。
被选中的这个线程中的reactor将通过select系统调用对该连接进行持续监听,一旦监听到有IO事件发生,便分发给该线程所对应的handler去处理…(后续处理过程一样的)

1.2.3.2 评估
  • 消除了单reactor所带来的潜在的性能瓶颈隐患。
  • 该方案看上去比前者复杂,其实其结构是清晰的,实施起来是简单的:
    • 主线程、子线程分工明确,主线程负责接收新连接,子线程负责事件处理。
    • 不必为主线程与子线程之间的通信而感到苦恼,因为数据流是由主线的单向流动到子线程中,即在子线程拿到新连接,监听并处理好一个IO事件后,不必将数据再返回给主线程,而是直接由子线程自己返回给客户端。

Netty、Memcache、Nginx均采用了此方案。
Nginx的方案与上面的并不完全相同,它选择去掉主线程部分,即连接的接收可以由每个子线程来完成。

2.Proactor模式

2.1 概述


执行流程:

  1. 进程通过Proactor Initiator借助Asynchronous Operatio Processor注册proactorhandler到内核上。
  2. 后面将由Asynchronous Operatio Processor 负责请求的接收与IO操作,一旦接收到IO事件,它将自动进行IO操作,当IO完成后,它将通知Proactor,然后Proactor再根据具体的事件类型回调handler进行处理。

2.2 评估

  • 实现了异步I/O,即数据的准备和由内核拷贝至用户缓冲区的过程均无需用户进程(或者CPU)参与。

目前仅有Windows系统平台完全实现系统级别下的了异步I/O——IOCP
Linux平台尽管也有POSIX定义的异步IO接口aio函数,但它是用户层面的实现,而且仅支持本地文件的异步IO操作,不支持网络I/O。但是,在Linux 5.1之后,又引入io_uring异步I/O操作接口,它绝对是一个实打实的系统基本的实现,并且也可以用于网络I/O,并且它无需中断即可实现I/O操作,非常惊艳。

3.两种模式的对比

  • reactor模式下,reactor所感知到的事件是待完成的I/O事件,后续handler处理需要先把数据由内核缓存拷贝至用户缓冲区中才能继续处理事件,这种I/O模式属于非阻塞式I/O同步I/O
  • proactor模式下,proactor所感知到的事件是已完成的I/O事件,即不需要handler再去拷贝数据了,而是直接去处理事件,这种I/O模式属于非阻塞式I/O异步I/O,效率更高。

参考文档

9.3 高性能网络模式:Reactor 和 Proactor


这篇关于Reactor模式Proactor模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1009343

相关文章

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者

springboot实战学习(1)(开发模式与环境)

目录 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 (3)前端 二、开发模式 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 Validation:做参数校验Mybatis:做数据库的操作Redis:做缓存Junit:单元测试项目部署:springboot项目部署相关的知识 (3)前端 Vite:Vue项目的脚手架Router:路由Pina:状态管理Eleme

状态模式state

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/state 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 在状态模式中,player.getState()获取的是player的当前状态,通常是一个实现了状态接口的对象。 onPlay()是状态模式中定义的一个方法,不同状态下(例如“正在播放”、“暂停

软件架构模式:5 分钟阅读

原文: https://orkhanscience.medium.com/software-architecture-patterns-5-mins-read-e9e3c8eb47d2 软件架构模式:5 分钟阅读 当有人潜入软件工程世界时,有一天他需要学习软件架构模式的基础知识。当我刚接触编码时,我不知道从哪里获得简要介绍现有架构模式的资源,这样它就不会太详细和混乱,而是非常抽象和易

使用Spring Boot集成Spring Data JPA和单例模式构建库存管理系统

引言 在企业级应用开发中,数据库操作是非常重要的一环。Spring Data JPA提供了一种简化的方式来进行数据库交互,它使得开发者无需编写复杂的JPA代码就可以完成常见的CRUD操作。此外,设计模式如单例模式可以帮助我们更好地管理和控制对象的创建过程,从而提高系统的性能和可维护性。本文将展示如何结合Spring Boot、Spring Data JPA以及单例模式来构建一个基本的库存管理系统