Nginx模块详解

1. Nginx模块综述

nginx的模块非常之多,可以认为所有代码都是以模块的形式组织,这包括核心模块和功能模块,针对不同的应用场合,并非所有的功能模块都要被用到,附录A给出的是默认configure(即简单的http服务器应用)下被连接的模块,这里虽说是模块连接,但nginx不会像apache或lighttpd那样在编译时生成so动态库而在程序执行时再进行动态加载,nginx模块源文件会在生成nginx时就直接被编译到其二进制执行文件中,所以如果要选用不同的功能模块,必须对nginx做重新配置和编译。对于功能模块的选择,如果要修改默认值,需要在进行configure时进行指定,比如新增http_flv功能模块(默认是没有这个功能的,各个选项的默认值可以在文件auto/options内看到):

1
[root@localhost nginx-1.2.0]# ./configure --with-http_flv_module

执行后,生成的objs/ngx_modules.c文件内就包含有对ngx_http_flv_module模块的引用了,要再去掉http_flv功能模块,则需要重新configure,即不带–with-http_flv_module配置后再编译生成新的nginx执行程序。通过执行./configure –help,我们可以看到更多的配置选项。
虽然Nginx模块有很多,并且每个模块实现的功能各不相同,但是根据模块的功能性质,可以将它们分为四个类别:
1, handlers:处理客户端请求并产生待响应内容,比如ngx_http_static_module模块,负责客户端的静态页面请求处理并将对应的磁盘文件准备为响应内容输出。
2, filters:对handlers产生的响应内容做各种过滤处理(即是增删改),比如模块ngx_http_not_modified_filter_module,对待响应内容进行过滤检测,如果通过时间戳判断出前后两次请求的响应内容没有发生任何改变,那么可以直接响应 “304 Not Modified”状态标识,让客户端使用缓存即可,而原本待发送的响应内容将被清除掉。
3, upstream:如果存在后端真实服务器,nginx可利用upstream模块充当反向代理(Proxy)的角色,对客户端发起的请求只负责进行转发(当然也包括后端真实服务器响应的回转),比如ngx_http_proxy_module就为标准的代理模块。
4, load-balance:在nginx充当中间代理时,由于后端真实服务器往往多于一个,对于某一次客户端的请求,如何选择对应的后端真实服务器来进行处理,这就有类似于ngx_http_upstream_ip_hash_module这样的模块来实现不同的负载均衡算法(Load Balance)。
对于这几类模块,我们马上会分别进行详细介绍并分析各自典型代表模块,不过在此之前先从nginx模块源码上来进行直观认识。前面讲过nginx的所有代码都是以模块形式进行组织,而封装nginx模块的结构体为ngx_module_s,定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Filename : ngx_conf_file.h
struct ngx_module_s {
ngx_uint_t ctx_index; //当前模块在同类模块中的序号
ngx_uint_t index; //当前模块在所有模块中的序号

ngx_uint_t version; //当前模块版本号

void *ctx; //指向当前模块特有的数据
ngx_command_t *commands; //指向当前模块配置项解析数组
ngx_uint_t type; //模块类型
//以下为模块回调函数,回调时机可根据函数名看出
ngx_int_t (*init_master)(ngx_log_t *log);

};
Filename : ngx_core.h
typedef struct ngx_module_s ngx_module_t;

结构体ngx_module_s值得关注的几个字段分别为ctx、commands、type,其中commands字段表示当前模块可以解析的配置项目,这在配置文件解析一章做过详细描述;表示模块类型的type值只有5种可能的值,而同一类型模块的ctx指向的数据类型也相同:

序号type值ctx指向数据类型
1NGX_CORE_MODULEngx_core_module_t
2NGX_EVENT_MODULEngx_event_module_t
3NGX_CONF_MODULENULL
4NGX_HTTP_MODULEngx_http_module_t
5NGX_MAIL_MODULEngx_mail_module_t

上表中第三列里的数据类型非常重要,它们的字段基本都是一些回调函数,这些回调函数会在其模块对应的配置文件解析过程前/中/后会适时的被调用,做一些内存准备、初始化、配置值检查、初始值填充与合并、回调函数挂载等初始工作,以ngx_http_core_module模块为例,该模块type类型为NGX_HTTP_MODULE,ctx指向的ngx_http_module_t结构体变量ngx_http_core_module_ctx:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Filename : ngx_http_core_module.c
static ngx_http_module_t ngx_http_core_module_ctx = {
ngx_http_core_preconfiguration, /* preconfiguration */
NULL, /* postconfiguration */

ngx_http_core_create_main_conf, /* create main configuration */
ngx_http_core_init_main_conf, /* init main configuration */

ngx_http_core_create_srv_conf, /* create server configuration */
ngx_http_core_merge_srv_conf, /* merge server configuration */

ngx_http_core_create_loc_conf, /* create location configuration */
ngx_http_core_merge_loc_conf /* merge location configuration */
};

根据上面代码注释,可以很明显的看出各个回调函数的回调时机,比如函数ngx_http_core_preconfiguration()将在进行http块配置解析前被调用,所以在ngx_http_block()函数里可以看到这样的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Filename : ngx_http.c
static char *
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

if (module->preconfiguration) {
if (module->preconfiguration(cf) != NGX_OK) {
return NGX_CONF_ERROR;
}
}

rv = ngx_conf_parse(cf, NULL);

if (module->postconfiguration) {
if (module->postconfiguration(cf) != NGX_OK) {
return NGX_CONF_ERROR;
}
}


至于这些回调函数内的具体逻辑,如前所述一般是一些初始或默认值填充工作,但也有回调函数挂载的设置,比如ngx_http_static_module模块的postconfiguration字段回调函数ngx_http_static_init()就是将自己的处理函数ngx_http_static_handler()挂载在http处理状态机上,但总体来看这毕竟都只是一些简单的初始准备工作,值得一提的还有ngx_http_core_create_main_conf、ngx_http_core_create_srv_conf、ngx_http_core_create_loc_conf这三个回调函数用来创建存储位于http块、server块、location块配置项的内存。

参考文献:

nginx核心讲解