1. 程式人生 > 其它 >《深入剖析ngx》——配置解析

《深入剖析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邏輯有模組定義,如