nginx架构总结--nginx源码系列(一)

来源:互联网 发布:菜刀 知乎 编辑:程序博客网 时间:2024/06/06 13:29

总述:
nginx自身是高度模块化设计的,我们可以方便的开发任何基于tcp的模块(比如http模块,mail模块)。
注: 一、开发一个nginx模块,必须遵守的原则有:1、实现模块开发的接口 2、不能有阻塞的系统调用
二、web服务器提高网络效率的方法有:1、使用长连接(keepalive)代替短连接,减少建立、关闭连接带来的开销
2、使用压缩算法来增加相同吞吐量下的信息携带量;3、使用缓存来减少网络交互次数
nginx总结起来就是一个框架和五类模块

一、nginx的模块化设计
nginx的框架代码只占少部分,主要负责建立进程模型并使各个模块有序的执行,当然还包括一系列资源初始化和回收(从某种意义上来说,nginx自定义的数据结构和对系统调用的封装也可以视为框架代码)。
所有的模块都遵循着同样的ngx_module_t接口设计规范

//ngx_module_s是模块的定义struct ngx_module_s {    //对于一类模块(由下面的type成员决定类别)而言,ctx_index标示当前模块在这类模块中的序号。    //这个成员常常是由管理这类模块的一个nginx核心模块设置的,对于所有的HTTP模块而言,ctx_index    //是由核心模块ngx_http_module设置的。    ngx_uint_t            ctx_index;    //index表示当前模块在ngx_modules数组中的序号。Nginx启动的时候会根据ngx_modules数组设置各个模块的index值    ngx_uint_t            index;     //spare系列的保留变量,暂未使用    ngx_uint_t            spare0;    ngx_uint_t            spare1;    ngx_uint_t            spare2;    ngx_uint_t            spare3;    //nginx模块版本,目前只有一种,暂定为1    ngx_uint_t            version;    //模块上下文,每个模块有不同模块上下文,每个模块都有自己的特性,而ctx会指向特定类型模块的公共接口。    //比如,在HTTP模块中,ctx需要指向ngx_http_module_t结构体。    void                 *ctx;    //模块命令集,将处理nginx.conf中的配置项    ngx_command_t        *commands;    //标示该模块的类型,和ctx是紧密相关的。它的取值范围是以下几种:    //NGX_HTTP_MODULE,NGX_CORE_MODULE,NGX_CONF_MODULE,    //NGX_EVENT_MODULE,NGX_MAIL_MODULE    ngx_uint_t            type;    //下面7个函数是nginx在启动,停止过程中的7个执行点    ngx_int_t           (*init_master)(ngx_log_t *log);         //初始化master    ngx_int_t           (*init_module)(ngx_cycle_t *cycle);     //初始化模块    ngx_int_t           (*init_process)(ngx_cycle_t *cycle);    //初始化进程    ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);     //初始化线程    void                (*exit_thread)(ngx_cycle_t *cycle);     //退出线程    void                (*exit_process)(ngx_cycle_t *cycle);    //退出进程    void                (*exit_master)(ngx_cycle_t *cycle);     //退出master    //保留字段,无用,可以使用NGX_MODULE_V1_PADDING来替换    uintptr_t             spare_hook0;    uintptr_t             spare_hook1;    uintptr_t             spare_hook2;    uintptr_t             spare_hook3;    uintptr_t             spare_hook4;    uintptr_t             spare_hook5;    uintptr_t             spare_hook6;    uintptr_t             spare_hook7;};

基本接口ngx_module_t只涉及模块的初始化、退出以及对配置项的处理。如上代码所示,ngx_module_t结构体作为所有模块的通用接口,只定义了init_master 、init_module、init_process、init_thread、exit_thread、exit_process、exit_master这七个回调方法,而init_master 、init_thread、exit_thread这三个方法目前没有使用,后两个是因为nginx目前没有使用线程(因为多线程代码实现更难控制)。他们负责模块的初始化和退出,同时他们可以处理核心结构体ngx_cycle_t(每个进程都有一个该结构体变量)。而ngx_command_t类型的commands数组指定了模块中的配置名和模块处理配置变量的方法,ctx是一个void*指针,他表示一类模块所特有的通用函数接口。
这里写图片描述
上图包括核心、事件、http、mail四类模块的ctx上下文(配置模块的ctx上下文为空),和ngx_command_t结构。
配置模块是唯一一种只有一个模块的模块类型,这是nginx最底层的模块,他指导着所有模块以配置项为核心来提供功能。因此,他是所有其他模块的基础(但是,单就conf模块对ngx_module_t接口的实现情况来说,他只是实现了include命令,以及进程退出时执行的一个回调方法)。
核心类型的模块一共只有六个:ngx_core_module、ngx_errlog、ngx_events_module、ngx_openssl_module、ngx_http_module、ngx_mail_module。非模块的框架代码只关注于如何调用六个核心模块(大部分nginx模块都是非核心模块)。

typedef struct {    ngx_str_t             name;                                         //模块名,即ngx_core_module_ctx结构体对象的    void               *(*create_conf)(ngx_cycle_t *cycle);             //解析配置项前,nginx框架会调用create_conf方法    char               *(*init_conf)(ngx_cycle_t *cycle, void *conf);   //解析配置项完成后,nginx框架会调用init_conf方法} ngx_core_module_t;

ngx_core_module_t上下文是以配置项的解析作为基础的,它提供了create_conf回调方法来创建存储配置项的数据结构,在读取nginx.conf配置文件时,会根据模块中的ngx_command_t把解析出的配置项存放在这个数据结构中;他还提供了init_conf回调方法,用于在解析完配置文件后,使用解析出的配置项初始化模块功能。(但是,很多核心模块,比如http,event,mail并没有实现这个接口,而是在解析配置的时候,比如解析http命令时,调用命令处理函数来创建数据结构和初始化模块功能,http还会在回调函数里创建http模块类型的上下文以及初始化http类的那些模块中的一些属性)。
配置模块和核心模块这两类模块是由nginx的框架代码所定义的,这里的配置模块是所有模块的基础,他实现了最基本的配置项解析功能(就是解析nginx.conf文件)。其他三类模块都不会与框架产生直接关系。事件,http,mail这三类模块,都在核心模块中各有一个模块作为自己的”代言人“,并在同类模块中还有一个作为核心业务与管理功能的模块。

注:每个ngx_listening_t都有一个ngx_connection_t与之对应,反过来则不然。这样是为了使监听套接字操作起来和 连接套接字一样。完全是为了使监听套接字上的事件(只有可读事件)处理和连接套接字统一。

0 0
原创粉丝点击