模块化设计
常见的说法就是把其定义为:以功能块为单位进行程序设计,实现其求解算法的方法。
模块化编程的一条原则:高内聚,低耦合。
Nginx模块化结构
主要分为:核心块,标准HTTP块,可选HTTP块,邮件服务模块以及第三方库模块等五大类。
Ubuntu下默认的目录结构
所有的配置文件都在/etc/nginx下,并且每个虚拟主机已经安排在了/etc/nginx/sites-available下
程序文件在/usr/sbin/nginx
日志放在了/var/log/nginx中并已经在/etc/init.d/下创建了启动脚本nginx
默认的虚拟主机的目录设置在了/var/www/nginx-default (有的版本 默认的虚拟主机的目录设置在了/var/www, 请参考/etc/nginx/sites-available里的配置)
Web请求处理机制
-
多进程方式
当服务器每接收一个客户端时,就由服务器的主进程生成一个子进程出来和该客户端建立连接进行交互,直到连接断开,该子进程就结束了。
早期的得到服务器采用“预生成进程”的机制。简单来说,他将生成子进程的时机提前,在客户端请求还没来到之前就预先生成好,当请求到来时,主进程分配一个子进程与之交互,交互完成后,该进程也不结束,而是被主进程管理起来等待下一个客户到来。 -
多线程方式
服务器接收一个客户端时,主进程就会派生一个线程出来和该客户进行交互。 -
异步方式
首先介绍一下:同步机制、异步机制以及阻塞和非阻塞。
同步机制:发送方发送请求后,需要等待接收方发回的响应后,才接着发送下一个请求。所有请求在服务器得到同步发送方和接收方对请求的处理步调是一致的。
异步机制:发送方发出一个请求后,不等待接收方响应这个请求,继续发送下个请求。所有来自发送方的请求形成一个队列,接收方处理完成后通知发送方。
Socket的阻塞方式:调用结果返回前,线程被挂起,知道调用结果被返回才进入就绪态。
非阻塞方式:调用结果不能马上返回,当前线程不会被挂起,立即返回执行下一个调用。
概念两两组合,产生了四个新概念:同步阻塞,异步阻塞,同步非阻塞,异步非阻塞(用的多)。 -
Nginx服务器处理请求:
结合多进程和异步非阻塞方式。
当某个工作进程接收到客户端的请求后,调用IO进行处理,如果不能立即得到结果,就去处理其他请求,而客户端在此期间无需等待相应,可以去处理其他事情;当IO调用结果返回后,就回通知此工作进程;该进程得到通知,暂时挂起当前处理的事务,去响应客户端请求。 -
事件处理机制
IO处理完成后会主动通知工作进程。select/poll/epoll等系统调用来支持这种想法。这些系统调用称为事件驱动型,可以让进程同时处理多个并发请求而不用去关心IO调用的具体状态。
Nginx服务器的事件驱动模型
- 事件驱动模型概述
事件驱动模型一般由时间收集器、时间发送器和事件处理器三部分基本单元组成,如下图。
当“事件发送器”每传递过来一个请求,“目标对象”就将其放入一个待处理事件的列表,使用非阻塞IO方式调用“事件处理器”来处理该请求。
事件驱动模型库
-
select库
创建所关注时间的描述符集合;调用底层提供的select函数等待事件发生;轮询所有事件描述符集合中的每一个事件描述符,检查是否有相应的事件发生。 -
poll库(为select库的优化)
-
epool库
把描述符列表的管理交给内核负责,一旦有某种事件发生,内核就把发生的事件的描述符列表通知给进程,避免了轮询整个描述符列表。 -
rtsig模型
工作进程会通过系统内核建立一个rtsig队列用于存放标记事件的发生;每个事件发生时,系统内核就会产生一个信号存放到rtsig队列中等待工作进程的处理。 -
kqueue模型
-
/dev/poll模型
-
eventport模型
Nginx服务器的架构
服务器架构如下图所示:
-
主进程
主要功能是与外界通信和对其内部其他进程进行管理。
读取Nginx配置文件并验证其有效性和正确性
建立、绑定、和关闭Socket
按照配置文件生成、管理和结束工作进程
接受外界指令
不中断服务,实现平滑重启,应用新配置
不中断服务,实现平滑升级,升级失败进行回滚处理
开启日志文件,获取文件描述符
编译和处理Perl脚本 -
工作进程
由主进程生成,生成数量可以配置,生存于主进程的整个生命周期。
接收客户端请求
将请求依次送入各个功能模块进行过滤处理
IO调用,获取相应数据
与后端服务器器通信,接受后端服务器的结果
数据缓存,访问缓存索引、查询和调用缓存数据
发送请求结果,响应客户端请求
接受主程序指令。。。。。。 -
缓存索引重建及管理进程
缓存索引重建进程在服务启动一段时间由主进程生成,在缓存元数据重建完成后自动退出。根据本地磁盘上的缓存文件在内存中建立索引元数据库。
缓存索引管理进程存在于主进程的整个生命周期,负责对缓存索引进行管理。在索引元数据更新完成后,对元数据是否过期做出判断。 -
进程交互
Master-Worker交互和Worker-Worker交互两种,都依赖于管道机制。 -
Run Loops事件处理循环事件
是指进程内部用来不停地调配工作,对事件进行循环处理的一种模型。