nginx的配置系统很灵活,不但支持模块自定义配置项,而且支持多级配置以及合并多级配置项。这样的设计使得nginx的配置在内存中的布局也是分成多级的,比较复杂。因此,这里采用一种自顶向下的方式进行逐级剖析。
这里需要先说明一下nginx指令的上下文环境以及有效上下文环境。nginx配置的上下文环境指的是指令在配置文件中的位置,比如配置文件全局,http块全局,http server块, mail块全局等。而nginx指令的有效上下文环境指的是指令在nginx配置文件中允许出现的位置。任何出现在其非有效上下文环境中的指令都会被nginx视为错误。
下面来看一段代码
struct ngx_cycle_s {
void ****conf_ctx;
...
};
ngx_cycle_s结构体的conf_ctx字段是nginx配置项的最顶层入口,它是一个四级指针。那么,该怎么去理解这个conf_ctx呢?
下面的代码片段是从ngx_init_cycle函数中提取出来的,我们分析一下它的逻辑:
cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));//ngx_max_module是当前配置下nginx允许的最大模块数
...
for (i = 0; cycle->modules[i]; i++) {
if (cycle->modules[i]->type != NGX_CORE_MODULE) {
continue;
}
module = cycle->modules[i]->ctx;
if (module->create_conf) {
rv = module->create_conf(cycle);
if (rv == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
cycle->conf_ctx[cycle->modules[i]->index] = rv;
}
}
可以看出,conf_ctx本身是一个数组,数组大小与当前配置下nginx允许的最大模块数一致。另外,这里还调用了类型为NGX_CORE_MODULE的模块ctx成员的create_conf回调函数,并且把返回值保存在模块在conf_ctx中对应的元素中。而这个create_conf回调函数是NGX_CORE_MODULE类型的模块实现配置环境创建的,也就是说,NGX_CORE_MODULE类型的模块的配置是保存在conf_ctx与其位置对应的元素中的。那么,哪些模块是NGX_CORE_MODULE呢?下表列出了到nginx-1.12.1为止的NGX_CORE_MODULE以及它们的源码文件和create_conf返回的实际类型:
ngx_core_module | nginx.c | ngx_core_conf_t * |
ngx_events_module | ngx_event.c | void *** |
ngx_openssl_module | ngx_event_openssl.c | ngx_openssl_conf_t * |
ngx_google_perftools_module | ngx_google_perftools_module.c | ngx_google_perftools_conf_t * |
ngx_http_module | ngx_http.c | ngx_http_conf_ctx_t * |
ngx_errlog_module | ngx_log.c | NULL |
ngx_mail_module | ngx_mail.c | ngx_mail_conf_ctx_t * |
ngx_regex_module | ngx_regex.c | ngx_regex_conf_t * |
ngx_stream_module | ngx_stream.c | ngx_stream_conf_ctx_t * |
ngx_thread_pool_module | ngx_thread_pool.c | ngx_thread_pool_conf_t * |
那么NGX_CORE_MODULE中的指令的有效上下文环境是什么呢?很容易可以想到,就是配置文件全局。也就是说,任何在NGX_CORE_MODULE类型的模块中定义的指令只能出现在配置文件最外层,不能出现在其它任何 位置。
到这里我们已经可以知道,出现在最外层的配置都会被直接保存在conf_ctx对应的元素指向的内存块中。下面是从conf_ctx的角度上看,各主要NGX_CORE_MODULE类型模块的内存布局图:
那么,非全局的配置会被保存在哪里呢?这与模块类型相关,不同类型的模块的配置内存布局各不相同,会在别的文章中单独分析。