整个ngx_http_block中的ngx_conf_parse配置解析完成,,后面主要对配置文件进行优化。
优化可以分为以下:
1 配置作用域合并
2location划分
3 http header回调初始化hash
4 初始化http收包回调函数
5 server中的server_name形成hash
本篇主要说配置合并的事情
配置作用域合并
主要是http、server、location,http作用域最大、server其次、location最精细化。合并的主要流程是,同一个模块中的上下文变量可以存在在不同的作用域,可以在配置文件中的http作用域,也可以在server作用域,还可以写在location作用域,如果该变量在server作用域没有设置,但是http作用域配置文件中设置了该值,那么server作用域的该值,就会被http作用域的合并掉,使用http作用的值,同理location和server合并。那么下面来看核心代码。
cmcf = ctx->main_conf[ngx_http_core_module.ctx_index]; //获取http中的main_conf[ngx_http_core_module.ctx_index] 中的信息,包括server信息
cscfp = cmcf->servers.elts;
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
mi = ngx_modules[m]->ctx_index;
/* init http{} main_conf's */
if (module->init_main_conf) { //调用每个http module的init_main_conf函数,来初始化那些用户没设置的值
rv = module->init_main_conf(cf, ctx->main_conf[mi]);
if (rv != NGX_CONF_OK) {
goto failed;
}
}
rv = ngx_http_merge_servers(cf, cmcf, module, mi);
if (rv != NGX_CONF_OK) {
goto failed;
}
}
主要是获取server上下文cscfp,遍历NGX_HTTP_MODULE调用模块的init_main_conf函数,进行初始化和ngx_http_merge_servers进行作用域合并。我们就列举最核心的模块ngx_http_core_module的init_main_conf和ngx_http_merge_servers,分析完ngx_http_core_module的这两个函数,你就会清楚作用域合并原理。
ngx_http_core_module的init_main_conf回调函数为ngx_http_core_init_main_conf函数,
static char *
ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_core_main_conf_t *cmcf = conf;
//如果未设置,给一个默认值
if (cmcf->server_names_hash_max_size == NGX_CONF_UNSET_UINT) {
cmcf->server_names_hash_max_size = 512;
}
//如果未设置,给一个默认值
if (cmcf->server_names_hash_bucket_size == NGX_CONF_UNSET_UINT) {
cmcf->server_names_hash_bucket_size = ngx_cacheline_size;
}
//.如果未设置,那么给一个默认值
cmcf->server_names_hash_bucket_size =
ngx_align(cmcf->server_names_hash_bucket_size, ngx_cacheline_size);
if (cmcf->variables_hash_max_size == NGX_CONF_UNSET_UINT) {
cmcf->variables_hash_max_size = 512;
}
if (cmcf->variables_hash_bucket_size == NGX_CONF_UNSET_UINT) {
cmcf->variables_hash_bucket_size = 64;
}
cmcf->variables_hash_bucket_size =
ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size);
if (cmcf->ncaptures) {
cmcf->ncaptures = (cmcf->ncaptures + 1) * 3;
}
return NGX_CONF_OK;
}
从上面函数可以看到,如果用户没有在配置文件设置该模块main作用域(即http作用域)相应的值,那么就给他们赋值一个默认值。
作用域合并函数:
cf是http上下文
cmcf是ngx_http_core_module在main的上下文(即http上下文)
module是遍历的模块(ngx_modules)
mi 是该模块在http上下文的索引,对应的是ngx_module[m]
ngx_http_merge_servers(cf,cmcf, module, mi)
核心代码:
for (s = 0; s < cmcf->servers.nelts; s++) {
/* merge the server{}s' srv_conf's */
ctx->srv_conf = cscfp[s]->ctx->srv_conf;
if (module->merge_srv_conf) {
rv = module->merge_srv_conf(cf, saved.srv_conf[ctx_index], /*http的srv_conf*/
cscfp[s]->ctx->srv_conf[ctx_index]);//server的srv_conf进行合并
if (rv != NGX_CONF_OK) {
goto failed;
}
}
if (module->merge_loc_conf) {
/* merge the server{}'s loc_conf */
ctx->loc_conf = cscfp[s]->ctx->loc_conf;
rv = module->merge_loc_conf(cf, saved.loc_conf[ctx_index],
cscfp[s]->ctx->loc_conf[ctx_index]);
if (rv != NGX_CONF_OK) {
goto failed;
}
/* merge the locations{}' loc_conf's */
clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
rv = ngx_http_merge_locations(cf, clcf->locations,
cscfp[s]->ctx->loc_conf,
module, ctx_index);
if (rv != NGX_CONF_OK) {
goto failed;
}
}
}
ngx_http_merge_servers调用者(外层函数)是对模块(ngx_modules)进行遍历,也就是说对每一个模块的每一个server都会进行处理。然后我们聚焦于ngx_http_merge_servers函数,主要是对于一个模块合并该模块的http、server、location不同上下文的变量,http->server->location会越来越精准化,就像是c++的作用域一样,http可以看作是http作用域,server可以看作是server作用域,location相当于块作用域,内层作用域可以隐藏到外层作用域和这里的合并是一个道理。
ngx_http_merge_servers核心的两个函数是merge_srv_conf和merge_loc_conf,merge_srv_conf主要合并http和server server上下文,merge_loc_conf主要合并http和server的loc上下文, ngx_http_merge_locations主要合并server和loc的loc上下文,同时该函数还进行location的递归调用,用于合并location中的location。