《深入剖析ngx》——配置解析

1. 配置格式定义

1.1 配置项

ngx定义了两种配置项,
简单,以 ; 结尾
复杂,以 {} 结尾

由于简单为;结尾,所以可以直接分行写

1.2 上下文


复杂匹配项有上下文,实现继承。

2. 指令定义

ngx定义了一些指令,模块自己可以定义指令。
如 daemon 指令

ngx定义指令对象为

  • name 指令名称
  • set 设置执行的回调方法(在解析配置时进行,传入用户配置的参数和指令上下文)
  • offset 转换后,配置值在结构体中的存放位置,对于不需要保存值的配置项,offset直接设置为0
  • type 定义指令格式(在配置文件中怎么写)
    包含三种类别
  1. 指令类型:NGX_CONF_FLAGS 表示指令为 布尔类型。NGX_CONF_BLOCK表示为复杂指针类型
  2. 指令参数个数:NGX_CONF_NOARGS, NGX_CONF_TAKE1, NGX_CONF_TAKE2 ... NGX_CONF_TAKE12 ... NGX_CONF_1MORE ...
  3. 指令可存在上下文:NGX_MAIN_CONF, NGX_EVENT_CONF, NGX_HTTP_LOC_CONF ...
  • conf 主要由 NGX_HTTP_MODULE 类型模块使用,表示指令在当前配置项的大致位置,取值 NGX_HTTP_MAIN_CONF_OFFSET, NGX_HTTP_SRV_CONF_OFFSET, NGX_HTTP_LOC_CONF_OFFSET,其他模块基本不使用,直接设置为0.
  • post 大多数时候为NULL。

每个模块把自己的指令 ngx_command_s 构成一个数组,并以 ngx_xxx_commands 形式命名,以ngx_null_command做哨兵。

3. 配置解析

ngx 使用 ngx_conf_parse 解析配置,

ngx_conf_read_token 解析读取一条指令,并将参数保存到 cf->args 中
ngx_conf_handler 调用 指令的set回调

整个解析流程如下

ngx_conf_read_token 解析方法




4. 配置信息结构组织


整个配置在 cycle->conf_ctx.
ngx 只创建了必须模块的配置对象,而有些核心模块不一定会用到,所以对于这些模块,若配置文件中使用了,才进行创建,如http模块。
ngx_conf_param ,根据命令行参数初始化conf.ctx
ngx_conf_parse, 根据配置文件初始化 conf.ctx

每个模块定义自己的创建函数,如ngx_core_module

NGX_CONF_UNSET 表示本变量没有被用户设置。

模块如果有默认值,可以定义init函数,在init函数中给属性赋默认值

如 ngx_core_module 的init函数

这样就创建出了如下结构

如下每次 指令set时,都会传递本指令的上下文conf,而不同级别的指令的上下文不同cf->ctx

cmd->type == NGX_DIRECT_CONF 时,这个模块就是核心模块,所以这时的 cf->ctx 就是 cycle->conf_ctx
所以就可以得到 配置项对象conf,并调用 set 已设置他,如下是可能的情况

有些核心模块不是 NGX_DRIECT_CONF,所以 conf 为指向 cycle->conf_ctx[i] 的指针。
如此,这些模块可以自己创建 配置上下文。

http模块分配,得到如下结构

ngx_http_conf_t 之所以有 main_conf, srv_conf, loc_conf 三个配置数组,是因为 http{}中可以写 这三种级别的配置。

若 http 上下文中使用了 ngx_http_auth_basic_module 和 ngx_http_charset_filter_module 则,会生成如下配置结构。

在解析http{} 中配置时,会修改 cf->ctx 为http配置块,

在解析server{}中配置时,会修改 cf->ctx 为server配置块

可以看出 http{}块的 main_conf[0] 指向 ngx_http_core_main_conf_t,ngx_http_core_main_conf_t.servers是一个数组,记录了本http{}块下所有 server{},
每个表示 server 块的 ngx_http_conf_ctx_t 的 main_conf_t 又指向自己 http{} 块。
每个server块下可以写 server级别和 location 级别配置项,所以 server上下文实现也有 srv_conf 和 loc_conf。


在进行server{}中配置项解析前,也会修改cf->ctx为 server的 ngx_http_conf_ctx_t.

对于loc配置,使用队列管理

如上,server上下文的 loc_conf[0] 指向 ngx_http_core_loc_conf_t,ngx_http_core_loc_conf_t.locations 是链表节点,让 server上下文用队列方式管理所有其下的 location{},而每个 ngx_http_core_loc_conf_t 表示一个location{},ngx_http_core_loc_conf_t.loc_conf 指向其location{}中所有的配置项,loc_conf[0] 又回指 ngx_http_core_loc_conf_t。

而location{}上下文 ngx_http_conf_ctx_t 被加入哈希表中,其main_conf指向包含本location{}的 server 对应的 main_conf, server_conf指向包含本 location{} 的 server_conf。

解析location{}中配置项前,先修改 cf->ctx为 对应的 ngx_http_conf_ctx_t

location{}下可以包含location{},实现方式也是用队列方式方式管理

当cf->ctx为server 或 location时,ngx_conf_handler的情况

confp指向的配置在前期已经 create了,所以可以直接修改。

cmd->conf的值为,比如


所以 (char *)cf->ctx + cmd->conf 就能找到对应的 loc_conf 或 server_conf 或 main_conf。
再根据模块的索引号,就能返回需要配置的 模块配置对象。

5. 配置的继承

ngx配置继承的逻辑:如果 本上下文定义了配置项,则优先使用本配置,否则使用上层配置,否则使用默认配置。

   119 static char *
   120 ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
   121 {

   233     /* parse inside the http{} block */
   234
   235     cf->module_type = NGX_HTTP_MODULE;
   236     cf->cmd_type = NGX_HTTP_MAIN_CONF;
   237     rv = ngx_conf_parse(cf, NULL);

          ...
   248     cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
   249     cscfp = cmcf->servers.elts;
   250
   251     for (m = 0; cf->cycle->modules[m]; m++) {
   252         if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
   253             continue;
   254         }
   255
   256         module = cf->cycle->modules[m]->ctx;
   257         mi = cf->cycle->modules[m]->ctx_index;
   258
   259         /* init http{} main_conf's */
   260
   261         if (module->init_main_conf) {
   262             rv = module->init_main_conf(cf, ctx->main_conf[mi]);
   266         }
   267
   268         rv = ngx_http_merge_servers(cf, cmcf, module, mi);
   272     }
        }

优先使用用户配置值设置配置项,再使用 默认配置值,再进行merge.


   559
   560 static char *
   561 ngx_http_merge_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
   562     ngx_http_module_t *module, ngx_uint_t ctx_index)
   563 {

   570     cscfp = cmcf->servers.elts;
   571     ctx = (ngx_http_conf_ctx_t *) cf->ctx;
   572     saved = *ctx;
   573     rv = NGX_CONF_OK;
   574
   575     for (s = 0; s < cmcf->servers.nelts; s++) {
   576
   577         /* merge the server{}s' srv_conf's */
   578
   579         ctx->srv_conf = cscfp[s]->ctx->srv_conf;
   580
   581         if (module->merge_srv_conf) {
   582             rv = module->merge_srv_conf(cf, saved.srv_conf[ctx_index],
   583                                         cscfp[s]->ctx->srv_conf[ctx_index]);
   587         }
   588
   589         if (module->merge_loc_conf) {
   590
   591             /* merge the server{}'s loc_conf */
   592
   593             ctx->loc_conf = cscfp[s]->ctx->loc_conf;
   594
   595             rv = module->merge_loc_conf(cf, saved.loc_conf[ctx_index],
   596                                         cscfp[s]->ctx->loc_conf[ctx_index]);
   601             /* merge the locations{}' loc_conf's */
   602
   603             clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
   604
   605             rv = ngx_http_merge_locations(cf, clcf->locations,
   606                                           cscfp[s]->ctx->loc_conf,
   607                                           module, ctx_index);
   611         }
   612     }
   619 }
   620

合并main{}中的server配置项到server{},合并main{}中location配置项到location{},合并server{}中location配置项到location{}。
具体merge逻辑有模块定义,如

posted on 2022-03-14 14:11  开心种树  阅读(1444)  评论(0编辑  收藏  举报