• Nginx 之三:nginx服务器模块、web请求处理机制及事件驱动模型、进程功能和进程间通信


    一:Nginx的模块化结构设计:

    1、核心模块:指的是nginx服务器运行当中必不可少的模块,这些模块提供了最基本最核心的服务,比如权限控制、进程管理、错误日志、事件驱动、正则表达式解析等,nginx的源码模块位于/root/nginx-1.8.1/src目录:

    复制代码
    [root@Server1 src]# pwd
    /root/nginx-1.8.1/src
    [root@Server1 src]# ls
    core   #核心模块
    event #事件模块
    http #http模块
    mail #邮件模块
    misc #其他模块
    os #系统模块
    复制代码

    2、标准HTTP模块:默认即被编译到了Nginx当中,除非使用--with-out-module_name参数声明不编译,如:

    复制代码
    ngx_http_core  #配置端口、URL分析、服务器响应错误处理,别名控制以及其他HTTP核心事物。
    ngx_http_auth_basic_module #基于http的认证
    ngx_http_access_module #基于IP地址的访问控制策略
    ngx_http_autoindex_module #处理以“/”结尾的请求并自动生成目录列表。
    ngx_http_browser_module #解析HTTP请求头中的”User-Agent“ 的值。
    ngx_http_charset_module#指定网页的编码。
    。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
    复制代码

    3、可选HTTP模块:

    复制代码
    ngx_http_perl_module #在nginx 的配置文件中可以使用perl脚本。
    ngx_http_flv_module  #支持flash多媒体信息文件传输。
    ngx_http_gzip_module #支持时时压缩
    ngx_http_image_filter_module #支持JPEG,GIF和PNG的图片的尺寸和旋转方向
    ngx_http_ssl_module  #支持对HTTPS/SSL的支持
    ngx_http_sub_module  #支持使用指定的字符串替换相应信息的中的信息
    复制代码

    4、邮件模块;默认没有编译,使用的场景也不多。

    复制代码
    ngx_mail_auth_http_module.c
    ngx_mail.c
    ngx_mail_core_module.c
    ngx_mail.h
    ngx_mail_handler.c
    ngx_mail_imap_handler.c
    ngx_mail_imap_module.c
    ngx_mail_imap_module.h
    ngx_mail_parse.c
    ngx_mail_pop3_handler.c
    ngx_mail_pop3_module.c
    ngx_mail_pop3_module.h
    ngx_mail_proxy_module.c
    ngx_mail_smtp_handler.c
    ngx_mail_smtp_module.c
    ngx_mail_smtp_module.h
    ngx_mail_ssl_module.c
    ngx_mail_ssl_module.h
    复制代码

    5、第三方模块:

    echo-nginx-module #支持在配置文件中使用echo、sleep、time即exec等类似shell命令。
    memc-nginx-module #对标准http模块ngx_http_memcached_module的扩展,支持set、add、delete等命令
    lua-nginx-module #支持lua脚本语言

    6、安装 echo-nginx-module 模块:

    6.1:模块地址: https://github.com/openresty/echo-nginx-module.git

    6.2:进到在nginx源码目录下,执行编译安装echo-nginx-module模块:

    cd nginx-1.8.1
    ./configure   --prefix=/usr/local/nginx/ --add-module=/home/tianqi/echo-nginx-module-master
    make
    make install

    6.3:配置nginx.conf:

    复制代码
    server {
            listen       80;
            server_name  hfnginx.chinacloudapp.cn;
            location / {
                root   html;
                index  index.html index.htm;
                echo $remote_addr;
                echo $remote_port;
                echo "zhangjie";
            }
    复制代码

    6.4:访问测试:

    6.5:Nginx模块组织工作图:

     

    二:web请求处理机制:

    1、多进程方式:服务器没接受到一个客户端请求就有服务器的主进程生成一个子进程响应客户端,直到用户关闭连接,这样的优势是处理速度快,子进程之间相互独立,但是如果访问过大会导致服务器资源耗尽而无法提供请求。

    2、多线程方式:与多进程方式类似,但是每收到一个客户端请求会有服务进程派生出一个线程来个客户方进行交互,一个线程的开销远远小于一个进程,因此多线程方式在很大程度减轻了web服务器对系统资源的要求,但是多线程也有自己的缺点,即当多个线程位于同一个进程内工作的时候,可以相互访问同样的内存地址空间,所以他们相互影响,一旦主进程挂掉则所有子线程都不能工作了,IIS服务器使用了多线程的方式,需要间隔一段时间就重启一次才能稳定。

    三:同步和异步、阻塞与非阻塞:

    1、同步与异步:主要是针对应用程序与内核的交互方式而言的:

    同步:进程发出数据后,等内核返回响应以后才继续下一个请求,即如果内核一直不返回数据,那么进程就一直等,直到天荒地老,死机error。

    异步:进程发出数据后,不等内核返回响应,接着处理下一个请求,Nginx是异步的。

    2、阻塞与非阻塞:

    可以理解为内核与IO设备的交互方式,当内核收到进程请求IO数据时候的处理方式:

    也可以简单理解为内核需要做一件事能不能立即得到返回应答,如果不能立即获得返回,需要等待,那就阻塞了,否则就可以理解为非阻塞。

    阻塞:IO调用不能立即返回结果,即一个进程发起的IO请求不能得到立即满足时,进程就要一直等到内核响应,内核要把数据从IO设备复制到内核空间,再返回给进程,这是阻塞。

    非阻塞:IO调用可以立即返回结果,一个进程发起的IO进程不能立即满足时,不在等待,而是一遍一遍的轮训查看IO是否完成。

    详细区别如下图所示:

    3、混合总结:

    3.1:同步阻塞:程序进程向内核发送IO请求后一直等待内核响应,如果内核处理请求的IO操作不能立即返回,则进程将一直等待并不再接受新的请求,并由进程轮训查看IO是否完成,完成后进程将IO结果返回给Client,在IO没有返回期间进程不能接受其他客户的请求,而且是有进程自己去查看IO是否完成,这种方式简单,但是比较慢,用的比较少。

    3.2:同步非阻塞:,进程向内核发送请IO求后一直等待内核响应,如果内核处理请求的IO操作不能立即返回IO结果,进程将不再等待,而且继续处理其他请求,但是仍然需要进程隔一段时间就要查看内核IO是否完成。

    3.3:异步阻塞:event-diver,进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核收到进程请求后进行的IO如果不能立即返回,就由内核等待结果,直到IO完成后内核再通知进程,此方式比较占用内核,因此也很少使用。

    3.4:异步非阻塞:AIO,进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核调用的IO如果不能立即返回,内核会继续处理其他事物,直到IO完成后将结果通知给内核,内核在将IO完成的结果返回给进程,期间进程可以接受新的请求,内核也可以处理新的事物,因此相互不影响,可以实现较大的同时并实现较高的IO复用,因此异步非阻塞使用最多的一种通信方式。

     四:Nginx支持的事件驱动模型:

     1、select:

    select库是在linux和windows平台都基本支持的 事件驱动模型库,并且在接口的定义也基本相同,只是部分参数的含义略有差异,最大并发限制1024,只最早期的事件驱动模型。

    2、poll:

     在Linux 的基本驱动模型,windows不支持此驱动模型,是select的升级版,取消了最大的并发限制,在编译nginx的时候可以使用--with-poll_module和--without-poll_module这两个指定是否编译select库。

    3、epoll:

    epoll是库是Nginx服务器支持的最高性能的事件驱动库之一,是公认的非常优秀的事件驱动模型,它和select和poll有很大的区别,epoll是poll的升级版,但是与poll的效率有很大的区别.
    epoll的处理方式是创建一个待处理的事件列表,然后把这个列表发给内核,返回的时候在去轮训检查这个表,以判断事件是否发生,epoll支持一个进程打开的最大事件描述符的上限是系统可以打开的文件的最大数,同时epoll库的IO效率不随描述符数目增加而线性下降,因为它只会对内核上报的“活跃”的描述符进行操作。

    4、rtsig:

    不是一个常用事件驱动,最大队列1024,不是很常用

    5、kqueue:

    用于支持BSD系列平台的高校事件驱动模型,主要用在FreeBSD 4.1及以上版本、OpenBSD 2.0级以上版本,NetBSD级以上版本及Mac OS X 平台上,该模型也是poll库的变种,因此和epoll没有本质上的区别,都是通过避免轮训操作提供效率。

     6、/dev/poll:

    用于支持unix衍生平台的高效事件驱动模型,主要在Solaris 平台、HP/UX,该模型是sun公司在开发Solaris系列平台的时候提出的用于完成事件驱动机制的方案,它使用了虚拟的/dev/poll设备,开发人员将要见识的文件描述符加入这个设备,然后通过ioctl()调用来获取事件通知,因此运行在以上系列平台的时候请使用/dev/poll事件驱动机制。

    7、eventport:

    该方案也是sun公司在开发Solaris的时候提出的事件驱动库,只是Solaris 10以上的版本,该驱动库看防止内核崩溃等情况的发生。

    五:Nginx 进程的功能和进程间的通信:

    1、主进程(woker process)的功能:

    复制代码
    读取Nginx 配置文件并验证其有效性和正确性
    建立、绑定和关闭socket连接
    按照配置生成、管理和结束工作进程
    接受外界指令,比如重启、升级及退出服务器等指令
    不中断服务,实现平滑升级,重启服务并应用新的配置
    开启日志文件,获取文件描述符
    不中断服务,实现平滑升级,升级失败进行回滚处理
    编译和处理perl脚本
    复制代码

    2、工作进程(woker process)的功能:

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

    3、Ninx进程间的通信:

    3.1:主进程和工作进程之间的通信:

    复制代码
        工作进程是有主进程生成的,主进程使用fork()函数,在Nginx服务器启动过程中主进程根据配置文件决定启动工作进程的数量,然后建立一张全局的工作表用于存放当前未退出的所有的工作进程,主进程生成工作进程后会将新生成的工作进程加入到工作进程表中,并建立一个单向的管道并将其传递给工作进程,该管道与普通的管道不同,它是由主进程指向工作进程的单项通道,包含了主进程想工作进程发出的指令、工作进程ID、工作进程在工作进程表中的索引和必要的文件描述符等信息。
        主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令,每个工作进程都有能力捕获管道中的可读事件,当管道中有可读事件的时候,工作进程就会从管道中读取并解析指令,然后采取相应的执行动作,这样就完成了主进程与工作进程的交互。
    复制代码

     3.2:工作进程与工作进程之间的通信:

        工作进程之间的通信原理基本上和主进程与工作进程之间的通信是一样的,只要工作进程之间能够取得彼此的信息,建立管道即可通信,但是由于工作进程之间是完全隔离的,因此一个进程想要直到另外一个进程的状态信息就只能通过主进程来设置了。
        为了实现工作进程之间的交互,主进程在生成工作进程只之后,在工作进程表中进行遍历,将该新进程的ID以及针对该进程建立的管道句柄传递给工作进程中的其他进程,为工作进程之间的通信做准备,当工作进程1向工作进程2发送指令的时候,首先在主进程给它的其他工作进程工作信息中找到2的进程ID,然后将正确的指令写入指向进程2的管道,工作进程2捕获到管道中的事件后,解析指令并进行相关操作,这样就完成了工作进程之间的通信。
  • 相关阅读:
    [转]C++中const、volatile、mutable的用法
    [转]pugixml使用教程
    [转]xml解析工具的效率比较QDomDocument、TinyXml-2、RapidXml、PugiXml
    [原][spark]帧序列的纹理UV索引,修改spark源码,改变纹理索引方式,支持常规帧序列
    [原][unreal][UE][spark]分析unreal engine 虚幻引擎的粒子编辑器:Cascade
    [转][C++]佛祖保佑,永无bug。C++ BUG解决方案
    [转]VS中的路径宏 OutDir、ProjectDir、SolutionDir各种路径含义
    [转]jsbsim基础概念
    [原][粒子特效][spark]调节器modifier
    项目管理(八)- 控制项目的范围
  • 原文地址:https://www.cnblogs.com/myblog1314/p/11162070.html
Copyright © 2020-2023  润新知