Nginx:Nginx服务器架构初探

三、Nginx服务器架构初探

1、模块化结构

1)、什么是模块化设计

  • 功能块是对模块的描述,一个模块就是一个功能块,应该只负责一个功能,在设计模式理论中类似于经常提高的单一职责原则
  • 如果要体现模块化,就免不了将程序进行分解,这也是模块化编程的另一个原则——自顶向下,逐步求精原则
  • 一个程序被分解为多个模块,那么它们之间一定要存在一定的依赖关系,但是这个依赖不能太强,否则也就不能称之为模块化了。于是,又涉及模块化编程的一条原则:高内聚、低耦合原则。事实上,在设计模式理论中,也有对应的一条设计原则叫迪米特原则

2)、Nginx模块化结构

Nginx涉及到的模块分为核心模块、标准HTTP模块、可选HTTP模块、邮件服务模块以及第三方模块等五大类

核心模块主要包含对两类功能的支持,一类是主体功能,包括进程管理、权限控制、错误日志记录、配置解析等,另一类是用于响应请求事件必须的功能,包括事件驱动机制、正则表达式解析等

查看Nginx编译的模块:

[root@localhost /]# cd /nginx_1158/nginx-1.15.8/objs/

ngx_modules.c文件包含了此版本Nginx快速编译后包括的所有固定模块的声明

#include <ngx_config.h>
#include <ngx_core.h>

extern ngx_module_t  ngx_core_module;
extern ngx_module_t  ngx_errlog_module;
extern ngx_module_t  ngx_conf_module;
extern ngx_module_t  ngx_regex_module;
extern ngx_module_t  ngx_events_module;
extern ngx_module_t  ngx_event_core_module;
extern ngx_module_t  ngx_epoll_module;
extern ngx_module_t  ngx_http_module;
extern ngx_module_t  ngx_http_core_module;
extern ngx_module_t  ngx_http_log_module;
extern ngx_module_t  ngx_http_upstream_module
...

由于使用extern关键字修饰,因此各模块均可以被其他模块访问

2、Nginx服务器的Web请求处理机制

1)、Web服务器常见的请求处理方式

A.多进程方式

多进程方式是指,服务器每当接收到一个客户端请求时,就由服务器主进程生成一个子进程出来和该客户端建立连接进行交互,直到连接断开,该子进程就结束了

优点:设计和实现相对简单,各个子进程之间相互独立,处理客户端请求的过程彼此不受到干扰,并且当一个子进程产生问题时,不容易将影响漫延到其他进程中,这保证了提供服务的稳定性。当子进程退出时,其占用资源会被操作系统回收,也不会留下任何垃圾

缺点:操作系统中生成一个子进程需要进行内存复制等操作,在资源和时间上会产生一定的额外开销

B.多线程方式

服务器每当接收到一个客户端时,会由服务器主进程派生一个线程出来和该客户端进行交互。由于操作系统产生一个线程的开销远远小于产生一个进程的开销,所以多线程方式在很大程度上减轻了Web服务器对系统资源的要求。多个线程位于同一个进程内,可以访问同样的内存空间,彼此之间相互影响,同时,在开发过程中不可避免地要由开发者自己对内存进行管理,其增加了出错的风险

C.异步方式

同步机制是指发送方发送请求后,需要等待接收到接收方发回的响应后,才接着发送下一个请求

异步机制是指发送方发送一个请求后,不等待接收方响应这个请求,就继续发送下个请求

在同步机制中,所有的请求在服务器端得到同步,发送方和接收方对请求的处理步调是一致的;在异步机制中,所有来自发送方的请求形成一个队列,接收方处理完成后通知发送方

阻塞和非阻塞用来描述进程处理调用的方式,在网络通信中,主要指网络套接字Socket的阻塞和非阻塞方式,而Socket的实质也就是IO操作。Socket的阻塞调用方式为,调用结果返回之前,当前线程从运行状态被挂起,一直等到调用结果返回之后,才进入就绪状态,获取CPU后继续执行;Socket的非阻塞调用方式中,如果调用结果不能马上返回,当前线程也不会被挂起,而是立即返回执行下一个调用

  • 同步阻塞方式:发送方向接收方发送请求后,一直等待响应;接收方处理请求时进行的IO操作如果不能马上得到结果,就一直等到返回结果后,才响应发送方,期间不能进行其他工作
  • 同步非阻塞方式:发送方向接收方发送请求后,一直等待响应;接收方处理请求时进行的IO操作如果不能马上得到结果,就立即返回,去做其他事情,但由于没有得到请求处理结果,不响应发送方,发送方一直等待。一直到IO操作完成后,接收方获得结果响应发送方后,接收方才进入下一个请求过程
  • 异步阻塞方式:发送方向接收方发送请求后,不用等待响应,可以接着进行其他工作;接收方处理请求时进行的IO操作如果不能马上得到结果,就一直等待返回结果后,才响应发送方,期间不能进行其他工作
  • 异步非阻塞方式:发送方向接收方发送请求后,不用等待响应,可以接着进行其他工作;接受方处理请求时进行的IO操作如果不能马上得到结果,也不等待,而是马上返回去做其他事情,当IO操作完成以后,将完成状态和结果通知接收方,接收方在响应发送方

2)、Nginx服务器如何处理请求

Nginx结合多进程机制和异步机制对外提供服务。异步机制使用的是异步非阻塞方式

每个工作进程使用了异步非阻塞方式,可以处理多个客户端请求。当某个工作进程接收到客户端的请求以后,调用IO进行处理,如果不能立即得到结果,就去处理其他的请求;而客户端在此期间也无需等待响应,可以去处理其他的事情;当IO调用返回结果时,就会通知此工作进程;该进程得到通知,暂时挂起当前处理的事务,去响应客户端请求

客户端请求数量增长、网络负载繁重时,Nginx服务器使用多进程机制能够保证不增长对系统资源的压力;同时使用异步非阻塞方式减少了工作进程在I/O调用上的阻塞延迟,保证了不降低对请求的处理能力

3)、Nginx服务器的事件处理机制

Nginx服务器的工作进程调用IO后,就去进行其他工作了;当IO调用返回后,会通知工作进程。那么IO调用是如何把自己的状态通知给工作进程的呢?

  • 方案一:让工作进程在进行其他工作的过程中间隔一段时间就去检查一下IO的运行状态,如果完成,就去响应客户端,如果未完成,就继续正在进行的工作
  • 方案二:IO调用在完成后能主动通知工作进程

select/poll/epoll/kqueue等这样的系统调用就是用来支持第二种解决方案的。这些系统调用,也常被称为事件驱动模型,它们提供了一种机制,让进程可以同时处理多个并发请求,不用关心IO调用的具体状态。IO调用完全由事件驱动模型来管理,事件准备好之后就通知工作进程事件已经就绪

3、Nginx服务器的事件驱动模型

事件驱动模型一般是由事件收集器、事件发送器和事件处理器三部分基本单元组成
在这里插入图片描述

Nginx服务器响应和处理Web请求的过程,就是基于事件驱动模型的,它包含了事件收集器、事件发送器和事件处理器等三部分基本单元。事件发送器每传递过来一个请求,目标对象就将其放入一个待处理事件的列表,使用非阻塞IO方式调用事件处理器来处理该请求

事件驱动处理库又被称为多路IO复用方法,最常见的包括以下三种:select模型、poll模型和epoll模型。Nginx服务器还支持rtsig模型、kqueue模型、dev/poll模型和eventport模型等

1)、select库

select库是各个版本的Linux和Windows平台都支持的基本事件驱动模型库

首先,创建所关注事件的描述符集合。对于一个描述符,可以关注其上面的读事件、写事件以及异常发生事件,所以要创建三类事件描述符集合,分别用来收集读事件的描述符、写事件的描述符和异常事件的描述符。其次,调用底层提供的select()函数,等待事件发生。然后,轮询所有事件描述符集合中的每一个事件描述符,检查是否有相应的事件发生,如果有,就进行处理

Nginx服务器在编译过程中如果没有为其指定其他高性能事件驱动模型库,它将自动编译该库

2)、poll库

poll库作为Linux平台上的基本事件驱动模型

poll与select的基本工作方式是相同的,都是先创建一个关注事件的描述符集合,再去等待这些事件发生,然后再轮询描述符集合,检查有没有事件发生,如果有,就进行处理。poll库与select库的主要区别在于,select库需要为读事件、写事件和异常事件分别创建一个描述符集合,因此在最后轮询的时候,需要分别轮询这三个集合。而poll库只需要创建一个集合,在每个描述符对应的结构上分别设置读事件、写事件或者异常事件,最后轮询的时候,可以同时检查这三种事件是否发生。可以说,poll1库是select库的优化实现

3)、epoll库

epoll库在Linux2.6以上的版本都可以使用它

首先,epoll库通过相关调用通知内核创建一个有N个描述符的事件列表;然后,给这些描述符设置所关注的事件,并把它添加到内核的事件列表中去,在具体的编码过程中也可以通过相关调用对事件列表中的描述符进行修改和删除。完成设置之后,epoll库就开始等待内核通知事件发生了。某一事件发生后,内核将发生事件的描述符列表上报给epoll库。得到事件列表的epoll库,就可以进行事件处理了

4)、rtsig模型

rtsig是Real-Time-Signal的缩写,是实时信号的意思。rtsig模型并不是常用的事件驱动模型,但Nginx服务器提供了使用实时信号对事件进行响应的支持

使用rtsig模型时,工作进程会通过系统内核建立一个rtsig队列用于存放标记事件发生(在Nginx服务器应用只能怪特指客户端请求发生)的信号。每个事件发生时,系统内核就会产生一个信号存放到rtsig队列中等待工作进程的处理

rtsig队列有长度限制,超过该长度后就会发生溢出。默认情况下,Linux系统事件信号队列的最大长度设置为1024,也就是同时最多可以存放1024个发生事件的信号。当rtsig队列发生溢出时,Nginx将暂时停止使用rtsig模型,而调用poll库处理未处理的事件,直到rtsig信号队列全部情况,然后再次启动rtsig模型,以防止新的溢出发生

4、设计架构概览

1)、Nginx服务器架构

在这里插入图片描述

Nginx服务器启动后,产生一个主进程,主进程执行一系列工作后产生一个或者多个工作进程。主进程主要进行Nginx配置文件解析、数据结构初始化、模块配置和注册、信号处理、网络监听生成、工作进程生成和管理等工作;工作进程主要进行进程初始化、模块调用和请求处理等工作,是Nginx服务器提供服务的主体

在客户端请求动态站点的过程中,Nginx服务器还涉及和后端服务器的通信。Nginx服务器将接收到的Web请求通过代理转发到后端服务器,由后端服务器进行数据处理和页面组织,然后将结果返回

Nginx服务器为了提高对请求的响应效率,进一步降低网络压力,采用了缓存机制,将历史应答数据缓存到本地。在每次Nginx服务器启动后的一段时间内,会启动专门的进程对本地缓存的内容重建索引,保证对缓存文件的快速访问

2)、Nginx服务器的进程

A.主进程

Nginx服务器启动时运行的主要进程,它的主要功能是与外界通信和对内部其他进程进行管理

B.工作进程

由主进程生成,主要工作有以下几项:

  • 接收客户端请求
  • 将请求依次送入各个功能模块进行过滤处理
  • IO调用,获取响应数据
  • 与后端服务器通信,接收后端服务器处理结果
  • 数据缓存,访问缓存索引、查询和调用缓存数据
  • 发送请求结果,响应客户端请求
  • 接收主程序指令,比如重启、升级和退出等指令

工作进程是Nginx服务器提供Web服务、处理客户端请求的主要进程,完成了Nginx服务器的主体工作

3)、缓存索引重建及管理进程

Cache模块主要由缓存索引重建和缓存索引管理两类进程完成工作。缓存索引重建进程是在Nginx服务启动一段时间之后(默认是1分钟)由主进程生成,在缓存元数据重建完成后就自动退出;缓存索引管理进程一般存在于主进程的整个生命周期,负责对缓存索引进行管理

缓存索引重建进程完成的主要工作是,根据本地磁盘上的缓存文件在内存中建立索引元数据库。该进程启动后,对本地磁盘上存放缓存文件的目录结构进行描述,检查内存中已有的缓存元数据是否正确,并更新索引元数据库

缓存索引管理进程主要负责在索引元数据更新完成后,对元数据是否过期做出判断

4)、进程交互

A.Master-Worker交互

工作进程是由主进程生成的。Nginx服务器启动以后,主进程根据配置文件决定生成的工作进程的数量,然后建立一张全局的工作进程表用于存放当前未退出的所有工作进程

在主进程生成工作进程后,将新生成的工作进程加入到工作进程表中,并建立一个单向管道并将其传递给该工作进程。该管道与普通的管道不同,它是由主进程指向工作进程的单向管道,包含了主进程向工作进程发出的指令、工作进程ID、工作进程在工作进程表中的索引和必要的文件描述符等信息

主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令。每个工作进程都有能力捕获管道中可读事件,当管道中有可读事件时,工作进程从管道读取并解析指令,然后采取相应的措施

B.Worker-Worker交互

只要工作进程之间能够得到彼此的信息,建立管道,即可通信。由于工作进程之间是相互隔离的,因此一个进程要想知道另一个进程的信息,只能通过主进程来设置了

主进程在生成工作进程后,在工作进程表中进行遍历,将该新进程的ID以及针对该进程建立的管道句柄传递给工作进程表中的其他进程,为工作进程之间的交互做准备。每个工作进程捕获管道中可读事件,根据指令采取响应的措施

当工作进程W1需要向W2发送指令时,首先在主进程给它的其他工作进程信息中找到W2的进程ID,然后将正确的指令写入指向W2的通道。工作进程W2捕获到管道中的事件后,解析指令并采取相应措施。这样就完成了Worker-Worker交互

5)、Run Loops事件处理循环模型

Run Loops指的是进程内部用来不停地调配工作,对事件进行循环处理的一种模型。该模型是一个集合,集合中的每一个元素称为一个Run-Loop。每个Run-Loop可运行在不同的模式下,其中可以包含它所监听的输入事件源、定时器以及在事件发生时需要通知的Run-Loop监听器。为了监听特定的事件,可以在Run Loops中添加响应的Run-Loop监听器。当被监听的事件发生时,Run-Loop会产生一个消息,被Run-Loop监听器捕获,从而执行预定的动作

Nginx服务器在工作进程中实现了Run-Loop事件处理循环模型的使用,用来处理客户端发来的请求事件

猜你喜欢

转载自blog.csdn.net/qq_40378034/article/details/87902862