首先看一下对应的结构化调用
Nginx模块非常之多,可以认为所有代码都是以模块的形式组织的,包括核心模块和功能模块,对于功能模块的选择,可以在进行configure主动指定,比如新增http_flv模块
./configure --with-http_flv_module
执行这个命令之后,生成的objs/ngx_modules.c源文件内就会包含对ngx_http_flv_module模块的引用
Nginx模块有很多,大体上可以分为4个类别
handlers:协同完成客户端请求的处理,产生响应数据,比如ngx_http_rewrite_module模块, 用于处理客户端请求的地址重写,ngx_http_static_module模块,负责处理客户端的静态页面请求,ngx_http_log_module模块,负责记录请求日志
filters:对于handlers产生的数据进行过滤处理,比如模块ngx_http_not_modified_filter_module
upstream:Nginx可以利用upstream模块充当反向代理的角色,对客户端发送的请求进行转发,比如ngx_http_proxy_module模块
load-balance:Nginx充当中间角色,由于后端真实服务器往往多于一个,比如ngx_http_upstream_ip_hash_module这样的load balance模块来实现不同的负载均衡算法
首先看一下模块的定义:
struct ngx_module_s {
//当前模块在同类模块中的序号
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;
//指向当前模块持有的数据,必须指向ngx_http_module_t接口
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);
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_http_module_t模块为例,明显可以看到各个函数的回调时机
static ngx_http_module_t ngx_http_core_module_ctx = {
ngx_http_core_preconfiguration, /* preconfiguration */
ngx_http_core_postconfiguration, /* 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 */
};
struct ngx_command_s {
//配置项名称
ngx_str_t name;
//配置项出现的位置 server{}/location{}
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;
};
假如我们现在定义一个简单的http模块
#define ngx_command_s ngx_command_t
static ngx_command_t ngx_http_mytest_commands[] = {
{
ngx_string("mytest"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF,
ngx_http_mytest,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL
},
ngx_null_command
}
ngx_http_mytest是ngx_command_t结构体中的set成员,当在某个配置项中出现了mytest配置项,Nginx将会调用ngx_http_mytest方法
static char *
ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
ngx_http_core_loc_conf_t *clcf;
//找到配置项所属的配置块
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
//当匹配上mytest之后,ngx_http_mytest_handler将会处理和这个请求
clcf->handler = ngx_http_mytest_handler;
return NGX_CONF_OK;
}
ngx_http_mytest_handler其实就是对应在11个处理阶段中需要做的事,这个我们后面在讨论
最后定义mytest模块
#define ngx_module_s ngx_module_t;
ngx_module_t ngx_http_mytest_module = {
NGX_MODULE_V1,
&ngx_http_mytest_module_ctx,
ngx_http_mytest_commands,
NGX_HTTP_MODULE,
NULL,
...
}
这样,mytest模块在编译时将会被加入到ngx_modules全局数组中,nginx在启动时,会调用所有模块的初始化回调方法
对模块做初始化
在nginx.c中的main函数
/* 初始化所有模块;并对所有模块进行编号处理 ngx_modules数却是在自动编译的时候生成的,位于objs/ngx_modules.c文件中 */
if (ngx_preinit_modules() != NGX_OK) {
return 1;
}
/**
* 初始化所有模块;并对所有模块进行编号处理;
*/
ngx_int_t
ngx_preinit_modules(void)
{
ngx_uint_t i;
for (i = 0; ngx_modules[i]; i++) {
ngx_modules[i]->index = i;
ngx_modules[i]->name = ngx_module_names[i];
}
ngx_modules_n = i;
ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES;
return NGX_OK;
}
//cycle贯穿整个nginx生命周期
cycle = ngx_init_cycle(&init_cycle);
//给模块分配内存
if (ngx_cycle_modules(cycle) != NGX_OK) {
ngx_destroy_pool(pool);
return NULL;
}
//调用module的初始化方法,回调方法
if (ngx_init_modules(cycle) != NGX_OK) {
/* fatal */
exit(1);
}
//最终开始回调
if (ngx_process == NGX_PROCESS_SINGLE) {
ngx_single_process_cycle(cycle);
} else {
ngx_master_process_cycle(cycle);
}