前言
考虑有如下形式的配置文件:
http{
....
server {
.....
location {
.....
}
}
}
根据前面的讲解,Nginx会为每个http块,server块和location块创建一个ngx_http_conf_ctx_t结构体。这个结构体主要是为了管理各个模块的main_conf,srv_conf,loc_conf。
我们知道,对于http块,Nginx会为每个模块创建他的main_conf,srv_conf,loc_conf;对与每个server块,Nginx会为每个模块创建srv_conf,loc_conf;对于每个location块,Nginx会为每个模块创建它的loc_conf。
按照朴素的想法,这种构建构建结构体的方式会导致很多冗余。比如在http块中,按道理应该只创建main_conf,而不必创建srv_conf和loc—_conf,而在server块中,只需要创建srv_conf,在location块中应该只创建loc_conf。这样才比较合理。但NGINX选择了这种冗余的创建方式,主要是基于灵活性的考虑:
- 可以在HTTP块中写srv类型和loc类型的配置项信息,在sever配置块中写loc类型的配置项信息。而不必限制一定要在server块中才能写srv类型的配置项信息,在location块中才能写loc类型的配置项信息。
- 根据前一篇博文中所述,由于server块对应的ngx_http_conf_ctx_t中的main_conf指向http块的main_conf数组,因此可以在server块中写main_conf类型的配置项。location同理。
- 由于可以在http块中写srv-conf配置项,server块中也可以写srv_conf配置项。所以相当于同一个配置项可以有多个值。然后我们可以选择使用哪个值。这就是merge的作用。
比如对于如下这样额配置:
http{
server_name="wen";
server {
server_name="guang";
}
}
对于srv_conf类型的配置项server_name的值,可以有两个选择。而merge过程就是决定选哪个作为最终的值。就是合并。
- 灵活性还来自下面这种写法:
http{
pp=12;
server {
server_name="wen";
}
server {
server_name="shan";
}
}
对于srv_conf类型的配置项pp,为了让所有server块中的模块的srv_conf配置结构体的pp项都包含相同的值,不需要在每个server块里面都写pp=12,只需要在最外层写就可以了,然后merge过程会把这个pp配置项的值merge到所有模块的drv_conf中。
下面我们具体讲一下merge的过程。
merge过程的实现
merge过程的入口是ngx_http_merge_servers
函数。
static char *
ngx_http_merge_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t