从Reactor模式俯瞰Nginx,你会发现你与高手的差距就在设计模式上

news2024/9/28 7:27:08

 我们知道了Nginx是做什么的以及它为何如此高效,以至于全宇宙拿它来做负载均衡或者说web server。

但是如果你只是了解了使用和知道了原理就认为已经掌握了它,那只能说你肤浅了,原理和使用技能看看大家都知道了,没必要拿出去和别人拽,但凡你和别人说Nginx的epoll我清楚,Master-Worker是如何工作的,初级选手可能觉得你真牛,你真厉害,可是碰到高手了,你那最多只是熟悉了这个组件而已,你并没有多大的成长,而高手通过对Nginx的深入了解,他能发现其中的秘籍,这个秘籍可以帮助他触类旁通其他组件,从而用最短的时间掌握更多的技术,在互联网领域立足不败之地。

那么高手是如何通过对Nginx的学习使自己达到更高的境界呢?

设计模式

别笑,学会了设计模式,你就可以自豪的说出金庸先生在《倚天屠龙记》里九阳真经的口诀:他强由他强,清风拂山岗;他横由他横,明月照大江。他自狠来他自恶,我自一口真气足。懂得人都懂,不懂的人自悟。

原谅我说这么多,请开始正题Reactor模式。

1. Reactor模式介绍

前面有写Reactor模式的文章,那篇文章主要是普及下概念,这次是重点介绍。

Reactor 模式,是指通过一个或多个输入同时传递给服务处理器的服务请求的事件驱动处理模式。服务端程序处理传入多路请求,并将它们同步分派给请求对应的处理线程,Reactor 模式也叫 Dispatcher 模式。

即I/O多路复用统一监听事件,收到事件后分发(Dispatch 给某进程),是编写高性能网络服务器的必备技术之一。

Reactor 模式中有 2 个关键组成:

  1. Reactor:Reactor在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对 IO 事件做出反应。它就像公司的电话接线员,它接听来自客户的电话并将线路转移到适当的联系人;
  2. Handlers:处理程序执行 I/O 事件要完成的实际事件,类似于客户想要与之交谈的公司中的实际官员。Reactor 通过调度适当的处理程序来响应 I/O 事件,处理程序执行非阻塞操作。

根据 Reactor 的数量和处理资源池线程的数量不同,有 3 种典型的实现:

  1. 单 Reactor 单线程
  2. 单 Reactor 多线程
  3. 主从 Reactor 多线程

下面详细介绍这 3 种实现方式。

2. 单 Reactor 单线程

 其中,Select是前面 I/O 复用模型介绍的标准网络编程API,可以实现应用程序通过一个阻塞对象监听多路连接请求,其他方案示意图类似。

方案说明:

  1. Reactor 对象通过 Select 监控客户端请求事件,收到事件后通过 Dispatch 进行分发;
  2. 如果是建立连接请求事件,则由 Acceptor 通过 Accept 处理连接请求,然后创建一个 Handler 对象处理连接完成后的后续业务处理;
  3. 如果不是建立连接事件,则 Reactor 会分发调用连接对应的 Handler 来响应;
  4. Handler 会完成 Read→业务处理→Send 的完整业务流程。
  • 优点:模型简单,没有多线程、进程通信、竞争的问题,全部都在一个线程中完成(Reactor单线程)。
  • 缺点:性能问题,只有一个线程,无法完全发挥多核 CPU 的性能。Handler 在处理某个连接上的业务时,整个进程无法处理其他连接事件,很容易导致性能瓶颈。

3. 单 Reactor 多线程

 方案说明:

  1. Reactor 对象通过 Select 监控客户端请求事件,收到事件后通过 Dispatch 进行分发;
  2. 如果是建立连接请求事件,则由 Acceptor 通过 Accept 处理连接请求,然后创建一个 Handler 对象处理连接完成后续的各种事件;
  3. 如果不是建立连接事件,则 Reactor 会分发调用连接对应的 Handler 来响应;
  4. Handler 只负责响应事件,不做具体业务处理,通过 Read 读取数据后,会分发给后面的 Worker 线程池进行业务处理;
  5. Worker 线程池会分配独立的线程完成真正的业务处理,最后将响应结果发给 Handler 进行处理;
  6. Handler 收到响应结果后通过 Send 将响应结果返回给 Client。
  • 优点:可以充分利用多核 CPU 的处理能力。
  • 缺点:多线程数据共享和访问比较复杂;Reactor 承担所有事件的监听和响应,在单线程中运行,高并发场景下容易成为性能瓶颈。

相关视频推荐

reactor 网络模型在开源框架中的应用

8个nginx面试题,助你了解nginx的底层设计

16万行Nginx源码,就该这么读

学习地址:c/c++ linux服务器开发/后台架构师

需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享

 

4. 主从 Reactor 多线程

 针对单 Reactor 多线程模型中,Reactor 在单线程中运行,高并发场景下容易成为性能瓶颈,可以让 Reactor 在多线程中运行。

方案说明:

  1. Reactor 主线程 MainReactor 对象通过 Select 监控建立连接事件,收到事件后通过 Acceptor 接收,处理建立连接事件;
  2. Acceptor 处理建立连接事件后,MainReactor 将连接分配 Reactor 子线程给 SubReactor 进行处理;
  3. SubReactor 将连接加入连接队列进行监听,并创建一个 Handler 用于处理各种连接事件;
  4. 当有新的事件发生时,SubReactor 会调用连接对应的 Handler 进行响应;
  5. Handler 通过 Read 读取数据后,会分发给后面的 Worker 线程池进行业务处理;
  6. Worker 线程池会分配独立的线程完成真正的业务处理,最后将响应结果发给 Handler 进行处理;
  7. Handler 收到响应结果后通过 Send 将响应结果返回给 Client。
  • 优点:
  1. 父线程与子线程的数据交互简单职责明确,父线程只需要接收新连接,子线程完成后续的业务处理。
  2. 父线程与子线程的数据交互简单,Reactor 主线程只需要把新连接传给子线程,子线程无需返回数据。
  • 缺点:代码写起来太复杂了:即编程复杂度较高。

5. Reactor小结

3种模式可以用个比喻来理解:(餐厅常常雇佣接待员负责迎接顾客,当顾客入坐后,侍应生专门为这张桌子服务)

  1. 单 Reactor 单线程,接待员和侍应生是同一个人,全程为顾客服务;
  2. 单 Reactor 多线程,1 个接待员,多个侍应生,接待员只负责接待;
  3. 主从 Reactor 多线程,多个接待员,多个侍应生。

Reactor 模式具有如下的优点:

  • 响应快,不必为单个同步时间所阻塞,虽然 Reactor 本身依然是同步的;
  • 编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;
  • 可扩展性,可以方便的通过增加 Reactor 实例个数来充分利用 CPU 资源;
  • 可复用性,Reactor 模型本身与具体事件处理逻辑无关,具有很高的复用性。

6. Nginx利用的就是主从Reactor模式

但它和主从reactor模式又有一定的区别,区别主要就是这个master进程,这个master进程不同于一般的主从式reactor(一般的主从式reactor设计会是主reactor负责将连接accept下来,然后再将连接fd挂载到子reactor中),这个master进程的主要任务就是监听信号的,也就是对nginx的一些命令做处理,然后再将这些处理通过sockerpair()或者信号等方式通知给worker进程,master进程同时监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。同时,这个master进程负责listen这个整个服务器的监听fd,然后worker进程通过竞争accept_mutex互斥锁来将连接从全连接队列里取出来,然后进行后续的事件循环处理。

也就是说除了Master与主从Reactor中的主线程Reactor不同以外,Worker的处理流程和子线程Reactor的处理流程几乎一摸一样,用陈硕老师的话来说就是reactors in process。

7. 小结

知道了Reactor模式之后再回头想想看看哪些你了解的服务或者中间件使用了此模式,要学会触类旁通才能更胜一筹,进而成为高手。这个模式还有一个最精妙的地方在于把复杂的问题通过"中间层"的方式简单化。计算机界不是有句老话:“凡是服务不能通过现有常规技术手段解决的,就加一个中间层来解决”。此话真的一语点醒梦中人,Reactor主从模式把频繁的accept过程,其他fd的并发IO处理过程以及业务处理逻辑部分分层,通过加层的方式让整个模式快速而高效的运行起来,这就是智慧,人类的智慧。

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

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

相关文章

快排递归、迭代的实现和两种优化方法

目录 快速排序 实现代码 时间复杂度 快排的优化 随机选择策略 三位取中法 非递归的快排 快速排序 快速排序算法是基于分治策略的一个排序算法,其基本思想是对于输入的子数组进行分解、递归求解,最后合并。 分解:以数组中左边第一个数作…

运行flutter doctor命令检测环境是否配置成功报错及解决方案

/** 运行flutter doctor命令检测环境是否配置成功,报如下错误**/ 1. cmdline-tools component is missing & Android licenses status unknown 1.1.安装cmdline-tools 1.2.配置android-licenses 运行命令flutter doctor --android-licenses,提示…

封装一个帧动画组件,使用的是精灵图

我写的是淘宝小部件,限制很多,用的是精灵图,说下大概思路,主要是通过背景图片的X Y轴去控制,首先创建一个组件 例: 然后在props定义需要的参数,可通过父组件传递修改 需要传入精灵图地址、单…

【云原生】Prometheus监控docker容器

部署node-exporter用于搜集硬件和系统信息 // 全部主机都要做 docker run -d -p 9100:9100 -v /proc:/host/proc -v /sys:/host/sys -v /:/rootfs --nethost prom/node-exporter --path.procfs /host/proc --path.sysfs /host/sys --collector.filesystem.ignored-mount-point…

Windows系统pagefile.sys删除、移动

背景 在使用windows系统中通常会发现c盘系统盘容量和实际容量不符。以至于你以为还有几十个G的空间,但操作程序时会出现空间不足的情况 。 例如以下错误: # There is insufficient memory for the Java Runtime Environment to continue. # Native memo…

【六】Netty Google Protobuf 编解码

Netty Google Protobuf 编解码Google Protobuf 介绍Protobuf 的入门Protobuf 开发环境搭建Protobuf 下载创建.proto文件第五节的 对应实体(SubscribeReq,SubscribeResp )SubscribeReq.proto 文件SubscribeResp.proto利用命令生成对应的java文…

详解c++---string模拟实现

这里写目录标题前言准备工作构造函数析构函数迭代器的实现插入数据有关的函数实现reservepush_backoperatorappendinserterasefindresize[ ]clear>>>>新式拷贝构造函数新式赋值重载前言 在前面的文章里我们学习了c中string的用法,那么这篇文章我们将带…

Vue的双向绑定(数据劫持)

双向绑定所谓的双向绑定其实就是,ui或者数据有一方做了修改,那么另外一个也会随着改变。简单来说,视图驱动数据,同时数据也能驱动视图。视图驱动数据,只需要绑定事件。数据驱动视图,则需要去对数据做监听&a…

DC-DC PCB layout经验-含走线宽度和载流量表格

在DC-DC芯片的应用设计中,PCB布板是否合理对于芯片能否表现出其最优性能有着至关重要的影响。不合理的PCB布板会造成芯片性能变差如线性度下降(包括输入线性度以及输出线性度)、带载能力下降、工作不稳定、EMI辐射增加、输出噪声增加等&#…

不同Nodejs版本的TypeScript的建议配置

Node Target Mapping microsoft/TypeScript Wiki GitHubTypeScript is a superset of JavaScript that compiles to clean JavaScript output. - Node Target Mapping microsoft/TypeScript Wikihttps://github.com/microsoft/TypeScript/wiki/Node-Target-Mapping以上是tsc…

SpringBoot+Vue项目知识管理系统

文末获取源码 开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7/8.0 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9 浏…

macOS 安装 Frama-C 及使用

操作系统:macOS 12.6 Monterey 官网安装指导:Get Frama-C 一、操作与避坑 🕳️ 1、macOS 包管理绕不开 Homebrew 工具,确保安装好。 2、安装 Frama-C 的必要依赖 brew install opam gmp gtk gtksourceview libgnomecanvas在安装…

MATLAB-最大值与最小值

在MATLAB中,用于计算最大值的函数是max函数,用于计算最小值的函数是min函数,其调用格式如下。Bmax(A) %计算最大值 ,若A为向量,则计算并返回向量中的最大值;若A为矩阵,则计算并返回%一个含有各列最大值的行…

从0到1完成一个Vue后台管理项目(九、引入Breadcrumb面包屑,更改bug)

往期 从0到1完成一个Vue后台管理项目(一、创建项目) 从0到1完成一个Vue后台管理项目(二、使用element-ui) 从0到1完成一个Vue后台管理项目(三、使用SCSS/LESS,安装图标库) 从0到1完成一个Vu…

ansible(第四天)

三:编写playbook 1.Ansible playbook 临时命令可以作为一次性对一组主机运行简单的任务。不过,若要真正发挥Ansible的力量,需要了解如 何使用playbook可以轻松重复的方式对一组主机执行多项复杂的任务。 play是针对对清单中选定的主机运行…

汽车电子系统网络安全组织管理

声明 本文是学习GB-T 38628-2020 信息安全技术 汽车电子系统网络安全指南. 下载地址 http://github5.com/view/764而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 汽车电子系统网络安全组织管理 6.1 组织机构设置 组织应高度重视网络安全&#xff0c…

基于Prometheus+Grafana搭建监控平台(Windows/Linux环境exporter部署)

1. 介绍 1.1 Prometheus是什么?Prometheus(普罗米修斯)是一个最初在SoundCloud上构建的监控系统。自2012年成为社区开源项目,拥有非常活跃的开发人员和用户社区。为强调开源及独立维护,Prometheus于2016年加入云原生云计算基金会…

【从零开始学习深度学习】43. 算法优化之Adam算法【RMSProp算法与动量法的结合】介绍及其Pytorch实现

Adam算法是在RMSProp算法基础上对小批量随机梯度也做了指数加权移动平均 【可以看做是RMSProp算法与动量法的结合】。 目录1. Adam算法介绍2. 从零实现Adam算法3. Pytorch简洁实现Adam算法--optim.Adam总结1. Adam算法介绍 Adam算法使用了动量变量vt\boldsymbol{v}_tvt​和RMS…

LVGL官方UI设计软件——SquareLine Studio micropython 使用简单测评

经常去LVGL官网逛的人一定都知道这个软件,作为官方的亲儿子,使用体验如何呢,我简单体验了一周左右,简单做个测评,本测评仅代表我个人意见,并且仅限micropython的使用体验! 首先是价格&#xff0…

TCP报文段(segment)首部格式

TCP传给IP的数据单元称作TCP报文段或简称为TCP段(TCP segment)。 IP传给链路层的数据单元称作IP数据报(IP datagram)。 通过以太网传输的比特流称作帧(Frame)。 逐层封装: 源端口号发送端端口号,字段长16位(2字节&…