nginx 的一大设计亮点就是可拓展, 可插拔的模块化架构; 在使用的时候, 我们可以根据自己业务的需求选择合适的模块组合;
本文涉及的源码基于 nginx 1.11.2.4;
nginx 模块相关数据结构
各数据结构的别名
1 | /* core/ngx_core.h */ |
指令数据结构 ngx_command_t
用于定义模块拥有什么可以设置的 关键字/指令 (directive), 如 ngx_http_core_module 中的 user, pid, master_process 等;1
2
3
4
5
6
7
8
9/* core/ngx_conf_file.h */
struct ngx_command_s {
ngx_str_t name; // 指令的命名
ngx_uint_t type; // 对指令的一些使用条件限定
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_uint_t conf; // 指令参数的存储位置
ngx_uint_t offset;
void *post;
};
其中, 最重要的是第二个参数 type, 它是对以下两类 条件限定 作了一个 按位或 操作:
- 指令允许在哪些 context 中使用;
- 指令所接收的参数情况(参数形态, 参数个数);
对第一类条件, 限定的 context 上下文, 常用的类型如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/* 主模块/全局相关: core/ngx_conf_file.h */
/* http 模块相关: http/ngx_http_config.h */
/* event 模块相关: event/ngx_event.h */
对第二类条件, 首先是参数形态, 可以有如下类型:1
2
3
然后是参数数目:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// 严格的参数数目
// 限定参数数目的下限
// 几种数目的组合
// 最大的参数数目限制
上下文数据结构 ngx_module_ctx
大致分为以下几类: core, http, event, mail;
ngx_conf_module 没有对应的 module context;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35/* core/ngx_module.h */
typedef struct {
ngx_str_t name;
void *(*create_conf)(ngx_cycle_t *cycle);
char *(*init_conf)(ngx_cycle_t *cycle, void *conf);
} ngx_core_module_t;
/* event/ngx_event.h */
typedef struct {
ngx_str_t *name;
void *(*create_conf)(ngx_cycle_t *cycle);
char *(*init_conf)(ngx_cycle_t *cycle, void *conf);
ngx_event_actions_t actions;
} ngx_event_module_t;
/* http/ngx_http_config.h */
typedef struct {
ngx_int_t (*preconfiguration)(ngx_conf_t *cf);
ngx_int_t (*postconfiguration)(ngx_conf_t *cf);
void *(*create_main_conf)(ngx_conf_t *cf);
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
void *(*create_srv_conf)(ngx_conf_t *cf);
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
void *(*create_loc_conf)(ngx_conf_t *cf);
char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_http_module_t;
/* mail/ngx_mail.h */
typedef struct {
ngx_mail_protocol_t *protocol;
void *(*create_main_conf)(ngx_conf_t *cf);
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
void *(*create_srv_conf)(ngx_conf_t *cf);
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_mail_module_t;
模块的类型
模块的类型都被定义为 无符号整型:1
2
3
4
5
6
7
8
9
10
11
12/* http/ngx_http_config.h */
/* core/ngx_conf_file.h */
/* mail/ngx_mail.h */
/* event/ngx_event.h */
模块定义数据结构 ngx_module_t
ngx_module_t 是 nginx module 的最终定义之处, 其中字段包括了上面提及的 ngx_module_ctx 上下文, ngx_command_t[] 可配置指令集, 模块的类型, 以及各种生命周期中的回调函数;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34/* core/ngx_module.h */
struct ngx_module_s {
// 以下字段常使用宏定义 NGX_MODULE_V1
ngx_uint_t ctx_index;
ngx_uint_t index;
char *name;
ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t version;
const char *signature;
// 需要自己定义的部分 (前 3 个必选, 后 7 个可为 NULL)
void *ctx; // 上下文数据结构
ngx_command_t *commands; // 指令集合
ngx_uint_t type; // 模块类型
ngx_int_t (*init_master)(ngx_log_t *log);
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);
// 以下字段常使用宏定义 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;
};
常用于填充的两个宏定义如下:1
2
3
4
5
6/*
* 申明 ngx_module_t 时常用的的宏定义
* core/ngx_module.h
*/
nginx 模块加载与查看
模块加载的时机
nginx 模块是在静态编译时加载的, 无法如 apache 一般使用动态链接库加载, 编译时指定选项以加载指定模块:1
2sudo /usr/local/nginx-1.11.2/configure --without-xxx_module --with-yyy_module
sudo make && sudo make install
nginx 编译完成后, 在 objs/ 目录下会自动生成模块加载的源文件 ngx_modules.c
与目标文件 ngx_modules.o
:1
2
3
4
5
6
7
8
9
10
11
12
13ngx_module_t *ngx_modules[] = {
&ngx_core_module,
&ngx_errlog_module,
&ngx_conf_module,
&ngx_openssl_module,
&ngx_regex_module,
&ngx_events_module,
&ngx_event_core_module,
&ngx_epoll_module,
&ngx_http_module,
&ngx_http_core_module,
...
};
nginx 已加载模块的查看
1 | > /usr/local/nginx/sbin/nginx -V |