前言


最近在读 Nginx 相关的书籍,做一下读书笔记。

Nginx 作为业界知名的高性能服务器,被广泛的应用。它的高性能正是由于其优秀的架构设计,其架构主要包括这几点:模块化设计、事件驱动架构、请求的多阶段异步处理、管理进程与多工作进程设计、内存池的设计,以下内容依次进行说明。

模块化设计


高度模块化的设计是 Nginx 的架构基础。在 Nginx 中,除了少量的核心代码,其他一切皆为模块。

所有模块间是分层次、分类别的,Nginx 官方共有五大类型的模块:核心模块、配置模块、事件模块、HTTP 模块、mail 模块。它们之间的关系如下:

在这 5 种模块中,配置模块和核心模块是与 Nginx 框架密切相关的。而事件模块则是 HTTP 模块和 mail 模块的基础。HTTP 模块和 mail 模块的 “地位” 类似,它们都是更关注于应用层面。

事件驱动架构


事件驱动架构,简单的说就是由一些事件发生源来产生事件,由事件收集器来收集、分发事件,然后由事件处理器来处理这些事件(事件处理器需要先在事件收集器里注册自己想处理的事件)。

对于 Nginx 服务器而言,一般由网卡、磁盘产生事件,Nginx 中的事件模块将负责事件的收集、分发操作;而所有的模块都可能是事件消费者,它们首先需要向事件模块注册感兴趣的事件类型,这样,在有事件产生时,事件模块会把事件分发到相应的模块中进行处理。

对于传统 web 服务器(如 Apache)而言,采用的所谓事件驱动往往局限在 TCP 连接建立、关闭事件上,一个连接建立以后,在其关闭之前的所有操作都不再是事件驱动,这时会退化成按顺序执行每个操作的批处理模式,这样每个请求在连接建立后都将始终占用着系统资源,直到关闭才会释放资源。这种请求占用着服务器资源等待处理的模式会造成服务器资源极大的浪费。如下图所示,传统 web 服务器往往把一个进程或线程作为时间消费者,当一个请求产生的事件被该进程处理时,直到这个请求处理结束时,进程资源都将被这一请求所占用。比较典型的例子如 Apache 同步阻塞的多进程模式就是这样的。

传统 web 服务器处理事件的简单模型(矩形代表进程):

Nginx 采用事件驱动架构处理业务的方式与传统的 web 服务器是不同的。它不使用进程或者线程来作为事件消费者,所谓的事件消费者只能是某个模块。只有事件收集、分发器才有资格占用进程资源,它们会在分发某个事件时调用事件消费模块使用当前占用的进程资源,如下图所示,该图中列出了 5 个不同的事件,在事件收集、分发者进程的一次处理过程中,这 5 个事件按照顺序被收集后,将开始使用当前进程分发事件,从而调用相应的事件消费者来处理事件。当然,这种分发、调用也是有序的。

Nginx 处理事件的简单模型:

由上图可以看出,处理请求事件时,Nginx 的事件消费者只是被事件分发者进程短期调用而已,这种设计使得网络性能、用户感知的请求时延都得到了提升,每个用户的请求所产生的事件会及时响应,整个服务器的网络吞吐量都会由于事件的及时响应而增大。当然,这也带来一定的要求,即每个事件消费者都不能有阻塞行为,否则将会由于长时间占用事件分发者进程而导致其他事件得不到及时响应,Nginx 的非阻塞特性就是由于它的模块都是满足这个要求的。

请求的多阶段异步处理


多阶段异步处理请求与事件驱动架构是密切相关的,也就是说,请求的多阶段异步处理只能基于事件驱动架构实现。多阶段异步处理就是把一个请求的处理过程按照事件的触发方式划分为多个阶段,每个阶段都可以由事件收集、分发器来触发。

处理获取静态文件的 HTTP 请求时切分的阶段及各阶段的触发事件如下所示:

这个例子中,该请求大致分为 7 个阶段,这些阶段是可以重复发生的,因此,一个下载静态资源请求可能会由于请求数据过大,网速不稳定等因素而被分解为成百上千个上图所列出的阶段。

异步处理和多阶段是相辅相成的,只有把请求分为多个阶段,才有所谓的异步处理。当一个时间被分发到事件消费者中进行处理时,事件消费者处理完这个事件只相当于处理完 1 个请求的阶段。什么时候可以处理下一个阶段呢?这只能等待内核的通知,即当下一次事件出现时,epoll 等事件分发器将会获取到通知,然后去调用事件消费者进行处理。

管理进程、多工作进程设计


Nginx 在启动后,会有一个 master 进程和多个 worker 进程。master 进程主要用来管理 worker 进程,包括接收来自外界的信号,向各 worker 进程发送信号,监控 worker 进程的运行状态以及启动 worker 进程。 worker 进程是用来处理来自客户端的请求事件。多个 worker 进程之间是对等的,它们同等竞争来自客户端的请求,各进程互相独立,一个请求只能在一个 worker 进程中处理。worker 进程的个数是可以设置的,一般会设置与机器 CPU 核数一致,这里面的原因与事件处理模型有关。Nginx 的进程模型,可由下图来表示:

在服务器上查看 Nginx 进程:

这种设计带来以下优点:

1) 利用多核系统的并发处理能力

现代操作系统已经支持多核 CPU 架构,这使得多个进程可以分别占用不同的 CPU 核心来工作。Nginx 中所有的 worker 工作进程都是完全平等的。这提高了网络性能、降低了请求的时延。

2) 负载均衡

多个 worker 工作进程通过进程间通信来实现负载均衡,即一个请求到来时更容易被分配到负载较轻的 worker 工作进程中处理。这也在一定程度上提高了网络性能、降低了请求的时延。

3) 管理进程会负责监控工作进程的状态,并负责管理其行为

管理进程不会占用多少系统资源,它只是用来启动、停止、监控或使用其他行为来控制工作进程。首先,这提高了系统的可靠性,当 worker 进程出现问题时,管理进程可以启动新的工作进程来避免系统性能的下降。其次,管理进程支持 Nginx 服务运行中的程序升级、配置项修改等操作,这种设计使得动态可扩展性、动态定制性较容易实现。

内存池的设计


为了避免出现内存碎片,减少向操作系统申请内存的次数、降低各个模块的开发复杂度,Nginx 设计了简单的内存池,它的作用主要是把多次向系统申请内存的操作整合成一次,这大大减少了 CPU 资源的消耗,同时减少了内存碎片。

因此,通常每一个请求都有一个简易的独立内存池(如每个 TCP 连接都分配了一个内存池),而在请求结束时则会销毁整个内存池,把曾经分配的内存一次性归还给操作系统。这种设计大大提高了模块开发的简单些,因为在模块申请内存后不用关心它的释放问题;而且因为分配内存次数的减少使得请求执行的时延得到了降低。同时,通过减少内存碎片,提高了内存的有效利用率和系统可处理的并发连接数,从而增强了网络性能。

————————————————
原文作者:JeffreyC
转自链接:https://learnku.com/articles/24539

深入 Nginx 之架构篇[转]的更多相关文章

  1. Nginx从入门到放弃-第5章 Nginx架构篇

    5-1 Nginx常见问题_架构篇介绍 5-2 Nginx常见问题_多个server中虚拟主机读取的优先级 5-3 Nginx常见问题_多个location匹配的优先级1 5-4 Nginx常见问题_ ...

  2. Web应用扩展系列(1):架构篇(转)

    原文:Web应用扩展系列(1):架构篇 在这篇文章中,我将尽量涵盖Web应用扩展或性能调优时可能会遇到的一些架构问题. 首先,让我们来统一一些名词或项目的概念,下文中我将列举在扩展Web应用时可能会遇 ...

  3. 使用docker部署nginx+tomcat架构(3):使用docker-compose简化部署操作

    经历了之前的两篇,我们已经大体上了解了docker部署容器的过程. 使用docker部署nginx+tomcat架构 使用docker部署nginx+tomcat架构():访问mysql数据库 不过, ...

  4. .NET Core资料精选:架构篇

    .NET 6.0 马上就要发布,高性能云原生开发框架.希望有更多的小伙伴加入大.NET阵营.这是本系列的第三篇文章:架构篇,喜欢的园友速度学起来啊. 本系列文章,主要分享一些.NET Core比较优秀 ...

  5. 分布式架构高可用架构篇_07_MySQL主从复制的配置(CentOS-6.7+MySQL-5.6)

    参考: 龙果学院http://www.roncoo.com/share.html?hamc=hLPG8QsaaWVOl2Z76wpJHp3JBbZZF%2Bywm5vEfPp9LbLkAjAnB%2B ...

  6. Nginx服务器架构简析

    一.Nginx的模块化 模块化结构的思想是一个很久的概念,但也正是成熟的思想造就了Nginx的巨大优越性. 我们知道Nginx从总体上来讲是有许多个模块构成的.习惯将Nginx分为5大模块分别为:核心 ...

  7. nginx——内存池篇

    nginx--内存池篇 一.内存池概述 内存池是在真正使用内存之前,预先申请分配一定数量的.大小相等(一般情况下)的内存块留作备用.当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续 ...

  8. MySQL性能调优与架构设计-架构篇

    架构篇(1) 读书笔记 1.Scale(扩展):从数据库来看,就是让数据库能够提供更强的服务能力 ScaleOut: 是通过增加处理节点的方式来提高整体处理能力 ScaleUp: 是通过增加当前处理节 ...

  9. 现代IM系统中的消息系统架构 - 架构篇

    https://mp.weixin.qq.com/s/sAlI8MCIKUSj5KbcT3W-Lw 现代IM系统中的消息系统架构 - 架构篇 原创: 木洛 云栖社区 1周前

  10. mysql 架构篇系列 3 复制运行状态监控与选项参数说明

    一. 概述 在上一篇中,搭建了一主一从的复制架构,这篇通过一些诊断方法来了解复制的运行状态和一些选项参数说明.上次mysql主从服务关机,今天在打开mysql服务,出现了错误信息. 1.首先 启动主从 ...

随机推荐

  1. 6. 配置项:relabel_config

    6.1relabel_config的位置 6.2 relabel_config参数详解 1.replace 2. keep 3.drop 6.labelkeep 7.hashmod 6.3 正则表达式 ...

  2. 单例bean与原型bean的区别

    在使用Spring开发时,Spring提供了五种scope,分别为singleton,prototype,request,session,global session. 上图为各个scope描述的官方 ...

  3. Linux-分区-fdisk-mkfs-mount

  4. Oracle 监控客户端的连接数量趋势

    Oracle 监控客户端的连接数量趋势 背景 前期简单总结了table方式将表信息展示出来的方法 但是感觉这样非常不直观. 想着能够做出一个趋势来. 时序数据库的最佳的使用方式. 之前的确是太靠自己的 ...

  5. [转帖]【oracle】oracle查询表存储大小和表空间大小

    目录 查看表分配的物理空间大小 查看表实际存储空间大小 查看每个表空间的大小 查看表空间大小及使用率 查看数据库中数据文件信息 查看临时表空间信息 oracle表大小有两种含义,即表分配的空间大小和实 ...

  6. [转帖]Linux下清理内存和Cache方法见下文:

    https://www.cnblogs.com/the-tops/p/8798630.html 暂时目前的环境处理方法比较简单: 在root用户下添加计划任务: */10 * * * * sync;e ...

  7. 一个监控数据的思考-sockets_used

    一个监控数据的思考-sockets_used 背景 最近跟踪一个项目问题. Grafana的监控了里面有一个tcp的使用监控 CurrEstab 的数据量是: 700-2000 左右 但是同时有一个非 ...

  8. [转帖]鹅厂微服务发现与治理巨作PolarisMesh实践-上

    文章目录 概述 定义 核心功能 组件和生态 特色亮点 解决哪些问题 官方性能数据 架构原理 资源模型 服务治理 基本原理 服务注册 服务发现 安装 部署架构 集群安装 SpringCloud应用接入 ...

  9. 在线获取所有依赖rpm包的方法

    背景 现在经常有一些不能上网的LInux机器但是需要安装一些软件. 但是有时候经常因为有依赖关系找不到的情况比较麻烦. 或者是一些公司的网络总是受限,网络速度非常慢. 下载安装非常折磨人. 这个时候就 ...

  10. 2021美亚杯团队赛write up

    个人赛与团队赛下载文件解压密码:MeiyaCup2021 加密容器解密密码: uR%{)Y'Qz-n3oGU`ZJo@(1ntxp8U1+bW;JlZH^I4%0rxf;[N+eQ)Lolrw& ...