高性能Server的基石:reactor反应堆模式

news2024/11/18 9:36:39

   业务开发同学只关心业务处理流程。但是我们开发的程序都是运行服务端server上,服务端server接收到IO请求后,是如何处理请求并最终进入业务流程的呢?这里不得不提到reactor反应堆模型。reactor反应堆模型来源于大师Doug Lea在 《Sacalable io in java》中的设计。nginx tomcat redis nodejs dubbo netty 等软件的网络处理模型都是用的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 模型则适合只需要支持少量连接的场景,数据库连接池使用的事这个模型。

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

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

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

相关文章

基于51单片机烟雾报警器数码管显示( proteus仿真+程序+设计报告+讲解视频)

基于51单片机烟雾报警器数码管显示( proteus仿真程序设计报告讲解视频) 仿真图proteus7.8及以上 程序编译器:keil 4/keil 5 编程语言:C语言 设计编号:S0067 1. 主要功能: 基于51单片机的烟雾报警器proteus仿真设…

AxureCloud配置文件详细介绍

AxureCloud配置文件详细介绍 原文地址:https://docs.axure.com/axure-cloud/business/custom-settings-json/ 通过修改 customsettings.json 可以修改AxureCloud私有部署的域名、端口、HTTPS、存储目录、是否开启插件等, 默认安装的路径为: C:\Program Files\Axure…

milvus Upsert api数据结构源码分析

Upsert api数据结构 该方法将实体更新插入到 Milvus 中。如果集合中已存在指定字段,则该操作将覆盖现有实体;如果指定值尚不存在,则插入新实体。 实现:先insert再delete,并限制不能修改主键列。 限制:主键的autoid必须是false。…

【JS逆向学习】猿人学 第三题 罗生门

逆向目标 网址: 目标:session请求 逆向分析 首先分析网络请求,我们发现每次的翻页请求都会有一个jssm请求 从启动器进去跟栈进去 现在观察一下cookie是否有变化,经观察没有发生变化,参数也没有加密,所…

Python打发无聊时光:10.用flask创造按键控制的网页小游戏

第一步:装flask库 在终端输入: pip install flask 第二步:完整代码 为了方便大家移植,我将HTML、CSS和JavaScript直接嵌到一个py文件中。 from flask import Flask, render_template_stringapp Flask(__name__)app.route(/) def game()…

智能水表预付费管理系统

智能水表预付费管理系统是当前智能水表技术的重要应用之一,结合了智能化管理和预付费功能,为水务公司和用户提供了便捷、高效的用水管理解决方案。该系统利用先进的科技手段,实现了水表抄表、计费和管理的自动化,为用户带来更便捷…

如何删除右键菜单中的WPS与百度网盘

WPS 打开"开始菜单" ,搜索WPS,打开文件位置双击 WPS Office 工具选择配置工具 百度网盘 同时按住 Win键 和 R键 在运行中输入 regedit 打开注册表 复制粘贴,转到下面两个文件,直接删除即可 计算机\HKEY_CLASSES…

nginx实现http反向代理及负载均衡

目录 一、代理概述 1、代理概念 1.1 正向代理(Forward Proxy) 1.2 反向代理(Reverse Proxy) 1.3 正向代理与反向代理的区别 2、同构代理与异构代理 2.1 同构代理 2.2 异构代理 2.3 同构代理与异构代理的区别 二、四层代…

设计模式(五)-观察者模式

前言 实际业务开发过程中,业务逻辑可能非常复杂,核心业务 N 个子业务。如果都放到一块儿去做,代码可能会很长,耦合度不断攀升,维护起来也麻烦,甚至头疼。还有一些业务场景不需要在一次请求中同步完成&…

计讯物联5G RedCap网关TG463化繁为简,推动5G赋能千行百业

5G RedCap,全称为Reduced Capability,即在5G的基础上,对部分功能进行化繁为简后形成的新技术标准,故又称轻量化5G。作为高性价比下的精简技术,5G RedCap技术具备成本低、低功耗、兼顾5G等特点,能够在确保应…

小程序--组件通信

一、父传子 与vue利用props类似,小程序是利用自定义属性:properties // components/my-nav/my-nav.js Component({// 小程序组件默认样式是隔离,addGlobalClass设置为true可允许外部修改样式options: {addGlobalClass: true,// 只要使用到具…

express+mysql+vue,从零搭建一个商城管理系统4--mysql数据库链接

提示:学习express,搭建管理系统 文章目录 前言一、创建express_service数据库二、安装mysql三、新建config文件夹四、新建config/db.js五、index.js引入db.js文件六、启动项目预览总结 前言 需求:主要学习express,所以先写service…

MarkDown实用技巧:MarkDown中如何实现换行?

MarkDown实用技巧:MarkDown中如何实现换行? 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程 👈 希望…

YOLOv8改进 | 独家创新篇 | 结合SOTA思想利用双主干网络改进YOLOv8(全网独家创新,最重磅的更新)

一、本文介绍 本文给大家带来的改进机制是结合目前SOTAYOLOv9的思想利用双主干网络来改进YOLOv8(本专栏目前发布以来改进最大的内容,同时本文内容为我个人一手整理全网独家首发 | 就连V9官方不支持的模型宽度和深度修改我都均已提供,本文内容支持YOLOv8全系列模型从n到x均可…

达梦数据库把日志数据按天统计不同状态的数据,实现字段行转列与根据id分组

1、这是日志表记录的数据,现在需要统计出每个app_id各个警告类型alarm_type的总数 2、先实现行转列,把三个alarm_type值转成列字段 SQL select app_id,count(CASE WHEN alarm_typeconcurrency THEN 1 ELSE null END) AS currentCount,count(CASE WHEN …

嵌入式学习第二十二天!(继续学习线程)

线程相关函数接口: 1. 线程分离属性: 线程结束后,自动回收线程空间 1. pthread_attr_init: int pthread_attr_init(pthread_attr_t *attr); 功能:线程属性初始化 2. pthread_attr_destroy: int pthread_…

【Linux】进程优先级以及Linux内核进程调度队列的简要介绍

进程优先级 基本概念查看系统进程修改进程的优先级Linux2.6内核进程调度队列的简要介绍和进程优先级有关的概念进程切换 基本概念 为什么会存在进程优先级?   进程优先级用于确定在资源竞争的情况下,哪个进程将被操作系统调度为下一个运行的进程。进程…

MFC 皮肤库配置

1.创建MFC 对话框 2.添加皮肤资源 添加资源 添加头文件 关闭SDL检测 添加静态库文件 修改字符集 添加头文件 将皮肤中的ssk文件加载到初始化实例中 > 运行即可

十三、Qt多线程与线程安全

一、多线程程序 QThread类提供了管理线程的方法:一个对象管理一个线程一般从QThread继承一个自定义类,重载run函数 1、实现程序 (1)创建项目,基于QDialog (2)添加类,修改基于QThr…

计算机网络-网络互连和互联网(四)

1.TCP协议: 传输控制协议,面向字节流按顺序连接,可靠,全双工,可变滑动窗口,缓冲累积传送。协议号为6。下面是TCP段(段头),TCP头(传输头)&#xf…