高并发Server的基石:reactor反应堆模式

  业务开发同学只关心业务处理流程。但是我们开发的程序都是运行服务端server上,服务端server接收到IO请求后,是如何处理请求并最终进入业务流程的呢?这里不得不提到reactor反应堆模型。nginx tomcat redis nodejs dubbo等软件的网络处理模型都是用的reactor反应堆模型。

前置知识

通用网络请求处理流程

一般所有的网络服务,一般分为如下几个步骤:

  • 读请求(read request)
  • 读解析(read decode)
  • 处理程序(process service)
  • 应答编码 (encode reply)
  • 发送应答(send reply)
C10K问题

C10K 问题是这样的:如何在一台物理机上同时服务 10000 个用户?这里 C 表示并发,10K 等于 10000。C10K问题早已解决,现在面临的是C10M问题。

网络IO

请添加图片描述

一次完整的网络IO流程

  • 用户A发起网络写操作
  • 用户B发起网络读操作
  1. 数据准备阶段:内核等待IO设备准备好数据
  2. 数据拷贝阶段:将数据从内核缓冲区拷贝到用户空间缓冲区

阻塞IO

读数据时,如果内核缓冲区没有数据,执行read()操作的线程会挂起在这里,不能做其他的事情

多路复用IO

  IO多路复用是一种高效的IO模型,它的特点是可以同时监控多个文件描述符,提高了应用程序对输入输出操作的管理能力。当用户进程使用select、poll或epoll等系统调用时,它会将需要监控的文件描述符传递给内核,然后内核会在所有文件描述符中寻找就绪的文件描述符,并返回给用户进程。用户进程再根据就绪的文件描述符进行相应的读写操作。

  IO多路复用的优点是可以使用一个线程或进程来处理多个文件描述符,避免了多线程或多进程的开销,提高了系统的并发性和可伸缩性。IO多路复用的缺点是需要额外的系统调用来管理文件描述符,而且在数据拷贝阶段仍然是阻塞的。IO多路复用比较适合网络编程,比如服务器端的并发处理。

两类经典的网络模式

基于线程(进程)的 Thread(Process)-per-connection

请添加图片描述

TPC是Thread Per Connection的缩写,其含义是指每次有新的连接就新建一个线程去专门处理这个连接的请求。

缺点:

  1. 每新增一个客户端需要服务端新开一个线程支持,线程是很重的资源。
  2. 线程多了后,线程上下文切换很耗cpu
  3. 连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在 Read 操作上,造成线程资源浪费。
基于事件驱动的Reactor模式
单reactor单线(进)程

请添加图片描述

使用场景:客户端的数量有限,业务处理非常快速,比如 Redis ,6.0版本前的redis采用此方案

所有的线程都在同一个线程中循环处理。如果某个请求耗时很长,那么其他的请求只能阻塞等待。

单reactor多线程

请添加图片描述

为了解决单reactor单线程模型的缺陷,多线程模型应运而生。多线程模型引入worker线程池来处理请求的业务逻辑。

绝大部分请求的耗时都是在process这个阶段,因此引入worker线程池对性能的改善十分有效。

当然,这种模型也有明显缺点,连接建立、IO 事件读取以及事件分发完全有单线程处理;比如当某个连接通过系统调用正在读取数据,此时相对于其他事件来说,完全是阻塞状态,新连接无法处理、其他连接的 IO、查询 IO 读写以及事件分发都无法完成。

多reactor多线(进)程

请添加图片描述

在多线程模型中,我们提到,其主要缺陷在于同一时间无法处理大量新连接、IO就绪事件;因此,将主从模式应用到这一块,就可以解决这个问题。

主从 Reactor 模式中,分为了主 Reactor 和 从 Reactor,分别处理 新建立的连接、IO读写事件/事件分发。

  • 一来,主 Reactor 可以解决同一时间大量新连接,将其注册到从 Reactor 上进行IO事件监听处理
  • 二来,IO事件监听相对新连接处理更加耗时,此处我们可以考虑使用线程池来处理。这样能充分利用多核 CPU 的特性,能使更多就绪的IO事件及时处理。

简言之,主从多线程模型由多个 Reactor 线程组成,每个 Reactor 线程都有独立的 Selector 对象。MainReactor 仅负责处理客户端连接的 Accept 事件,连接建立成功后将新创建的连接对象注册至 SubReactor。再由 SubReactor 分配线程池中的 I/O 线程与其连接绑定,它将负责连接生命周期内所有的 I/O 事件。

类比

3 种模式可以用个比喻来理解:(餐厅常常雇佣前台接待员负责迎接顾客,当顾客入坐后,服务员专门为这张桌子服务,点好菜后,厨师负责做饭)

  • 1)单 Reactor 单线程,前台接待员、服务员、厨子是同一个人,全程为顾客服务;
  • 2)单 Reactor 多线程,前台接待员和服务员是一个人,厨师有多个;
  • 3)主从 Reactor 多线程,一个前台接待员负责,多个服务员,多个厨师
reactor线程模型

请添加图片描述

  • Acceptor:请求接收者,作用是在特定端口建立监听。
  • Main Reactor Thread Pool:主 Reactor 模型,主要负责处理 OP_ACCEPT 事件(创建连接),通常一个监听端口使用一个线程。在具体实践时,如果创建连接需要进行授权校验(Auth)等处理逻辑,也可以直接让 Main Reactor 中的线程负责。
  • Subreactor Thread Group( IO 线程组):在 Reactor 模型中也叫做从 Reactor,主要负责网络的读与写。当 Main Reactor Thread 线程收到一个新的客户端连接时,它会使用负载均衡算法从 NIO Thread Group 中选择一个线程,将 OP_READ、OP_WRITE 事件注册在 NIO Thread 的事件选择器中。接下来这个连接所有的网络读与写都会在被选择的这条线程中执行。
  • IO Thread:IO 线程。负责处理网络读写与解码。IO 线程会从网络中读取到二进制流,并从二进制流中解码出一个个完整的请求。业务线程池:通常 IO 线程解码出的请求将转发到业务线程池中运行,业务线程计算出对应结果后,再通过 IO 线程发送到客户端。
  • Worker thread pool: 业务线程池,处理具体的业务

reactor bio对比

NIO 模型更适合需要大量在线活跃连接的场景,常见于服务端;BIO 模型则适合只需要支持少量连接的场景

代码实现:https://github.com/bruce256/NIO

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/699405.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SwiftUI 支持拖放功能的集合视图(Grid)如何捕获手指按下并抬起这一操作

功能需求 假设我们开发了一款 SwiftUI 应用,其中用户可以通过拖放 Grid 中的 Cell 来完成一些操作。现在,我们希望用户在某个 Cell 被按下并随后抬起手指时得到通知,这能够实现吗? 如上图所示,我们准确地捕获到了手指在 Grid 的 Cell 上按下再抬起这一操作!那么它是如何…

Linux之ACL访问控制列表

一、ACL权限的介绍 1.1 什么是ACL 访问控制列表(ACL)是一种网络安全技术,它通过在网络设备(如路由器、交换机和防火墙)上定义一系列规则,对进出接口的数据包进行控制。这些规则可以包含“允许”&…

123 Linux C++ 系统编程2 Linux 上安装卸载程序三种方法,linux 下解压缩命令 tar介绍。kill命令,top命令,umask 命令

一 通过命令和网络直接安装 sudo apt-get update sudo apt-get update 的工作就是将自己本地 ubutun的软件列表和 aliyun 的软件列表对比,如不一样,则更新。 sudo apt-get install 软件名 真正的安装 那么这里就有一个问题了, 怎么从aliy…

【初始RabbitMQ】死信队列的实现

死信的概念 死信,顾名思义就是无法被消费的消息,字面意思可以这样理解,一般来说,producer 将消息投递到 broker 或者直接到 queue 里了,consumer 从 queue 取出消息 进行消费,但某些时候由于特定的原因导致…

认识HarmonyOS

1.认识HarmonyOS 1.1.HarmonyOS简介 在中美贸易战的刺激下,国产操作系统HarmonyOS(鸿蒙操作系统)开始进入到大众的视野。 鸿蒙寓意为“万物起源”,发展至今已经经过了好几个迭代版本。 1.1.1.早期鸿蒙雏形 LiteOS 2015 年 5 月 …

STM32F103x 的时钟源

AHB (Advanced High-performance Bus) 高速总线,用来接高速外设的。 APB (Advanced Peripheral Bus) 低速总线,用来接低速外设的,包含APB1 和 APB2。 APB1:上面连接的是低速外设,包括电源接口、备份接口、 CAN 、 US…

【Linux网络】网络编程套接字(TCP)

目录 地址转换函数 字符串IP转整数IP 整数IP转字符串IP 关于inet_ntoa 简单的单执行流TCP网络程序 TCP socket API 详解及封装TCP socket 服务端创建套接字 服务端绑定 服务端监听 服务端获取连接 服务端处理请求 客户端创建套接字 客户端连接服务器 客户端…

QT-串口工具

一、演示效果 二、关键程序 &#xff1a; #include "mainwindow.h" #include "ui_mainwindow.h"#include <QMessageBox>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow),listPlugins(QList<TabPluginInt…

动态规划--持续更新篇

将数字变成0的操作次数 1.题目 2.思路 在numberOfSteps函数中&#xff0c;首先设置f[0]为0&#xff0c;因为0已经是0了&#xff0c;不需要任何步骤。然后&#xff0c;使用一个for循环从1迭代到输入的整数num。对于每个整数i&#xff0c;如果i是奇数&#xff0c;则将f[i]设置为…

静态时序分析:SDC约束命令set_driving_cell详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 在上文中&#xff0c;我们不建议使用set_drive命令而是使用set_driving_cell命令&#xff0c;这是一个描述输入端口驱动能力更精确的方法。因为大多数情况下&…

SpringBoot实现缓存预热的几种常用方案

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&…

QEMU开发入门

1. 简介 QEMU&#xff08;Quick EMUlator&#xff09;是一个开源的虚拟化软件&#xff0c;它能够模拟多种硬件平台&#xff0c;并在这些平台上运行各种操作系统。QEMU可以在不同的主机架构之间进行虚拟化&#xff0c;例如x86、ARM、PowerPC、Risc-V等。QEMU是一个功能强大且灵…

LabVIEW开发FPGA的高速并行视觉检测系统

LabVIEW开发FPGA的高速并行视觉检测系统 随着智能制造的发展&#xff0c;视觉检测在生产线中扮演着越来越重要的角色&#xff0c;尤其是在质量控制方面。传统的基于PLC的视觉检测系统受限于处理速度和准确性&#xff0c;难以满足当前生产需求的高速和高精度要求。为此&#xf…

ACL权限、特殊位与隐藏属性的奥秘

1.2 操作步骤 # 1. 添加测试目录&#xff0c;用户&#xff0c;组&#xff0c;并将用户添加到组 ------------------- [rootlocalhost ~]# mkdir /project[rootlocalhost ~]# useradd zs[rootlocalhost ~]# useradd ls[rootlocalhost ~]# groupadd tgroup[rootlocalhost ~]# g…

软件提示找不到MSVCP140.dll是什么意思,修复MSVCP140.dll丢失的多个方法

msvcp140.dll 文件是 Microsoft Visual C 运行时库的一部分&#xff0c;具体来说它是 Visual Studio 2015 版本编译的C应用程序所依赖的一个动态链接库&#xff08;DLL&#xff09;文件。这个 DLL 文件包含了大量由Microsoft开发的标准C库函数&#xff0c;这些函数对于许多在Wi…

大模型综述总结--第一部分

1 目录 本文是学习https://github.com/le-wei/LLMSurvey/blob/main/assets/LLM_Survey_Chinese.pdf的总结&#xff0c;仅供学习&#xff0c;侵权联系就删 目录如下图 本次只总结一部分&#xff0c;刚学习有错请指出&#xff0c;VX关注晓理紫&#xff0c;关注后续。 2、概述…

红日靶场3

靶场链接&#xff1a;漏洞详情 在虚拟机的网络编辑器中添加两个仅主机网卡 信息搜集 端口扫描 外网机处于网端192.168.1.0/24中&#xff0c;扫描外网IP端口&#xff0c;开放了80 22 3306端口 80端口http服务&#xff0c;可以尝试登录网页 3306端口mysql服务&#xff0c;可…

linux卸载mysql8重装5

目录 背景操作卸载重装配置启动 背景 在linux&#xff08;阿里云ECS&#xff09;安装部署Hive时初始化Hive元数据库&#xff0c;遇到报错前一天两三小时没解决&#xff0c;问题定位为mysql&#xff0c;次日打算重装 操作 卸载 停止 MySQL 服务 systemctl stop mysql yum卸载…

ES6内置对象 - Map

Map&#xff08;Map对象保存键值对&#xff0c;键值均不限制类型&#xff09; 特点&#xff1a; 有序&#xff08;Set集合是无序的&#xff09;&#xff1b;键值对&#xff08;键可以是任意类型&#xff09;&#xff1b;键名不能重复&#xff08;如果重复&#xff0c;则覆盖&…

c编译器学习07:minilisp编译器改造(debug模式支持调试)

问题 原版的minilisp编译器不支持argv输入测试&#xff0c;不方便单步调试。 代码改造目标是既不改变原有程序的各种功能&#xff0c; 又能支持个人习惯的vs单步debug模式。 CMakeLists.txt变更 定义DEBUG宏 解决单步调试源码定位偏差问题 cmake_minimum_required(VERSION …