在NGINX的启动流程中,ngx_init_cycle是重点之一,而在ngx_init_cycle中,配置文件的解析又是重点中的重点。本文重点记录core域,event域,http域配置加载逻辑,主要记录个人重点关注的部分。

一、配置文件结构(命令类型)

配置文件每行(非注释行)的首个单词,当做是一个指令command(cmd);单行配置以分号为一行结束,以{}表示一个配置块,一个块中可以嵌套其他的块。

disconf nginx配置 nginx dynamic module_html

二、module基本静态配置

本文暂不做动态添加模块的相关笔记,NGINX初始提供一个默认的静态module数组,里面包含core域,events域,http域的默认模块列表。objs/ngx_modules.c

disconf nginx配置 nginx dynamic module_html_02


每个模块都用extern修饰,说明是引用的全局变量,比如ngx_core_module(nginx.c中定义):

disconf nginx配置 nginx dynamic module_apache_03


基本每个模块都采用这种方式的配置,不同的是各种方法指针和配置conf结构体的不同。

command->type采用多个标识合并的方式如:NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,
NGX_MAIN_CONF: 0001000000000000000000000000
NGX_DIRECT_CONF:0000000000010000000000000000
NGX_CONF_FLAG: 0000000000000000001000000000
type的值就为: 0001000000010000001000000000
然后用每个标识的值与type 进行&操作,就能判断type属不属于这个标识的类型
type & NGX_CONF_FLAG = 0001000000010000001000000000 & 0000000000000000001000000000 = 0000000000000000001000000000(NGX_CONF_FLAG)

三、ngx_cycle_modules模块加载
在进入ngx_init_cycle方法前,会通过ngx_preinit_modules()方法,对每个模块的index和name赋值;
在ngx_preinit_modules进入ngx_conf_parse()前,会先再ngx_cycle_modules()中,将静态的module拷贝到cycle的modules中

四、core域module配置创建

完成ngx_cycle_modules拷贝之后,会对core域的模块优先创建配置ngx_cycle.c 231-246行

disconf nginx配置 nginx dynamic module_apache_04


此时的配置结构如下:

disconf nginx配置 nginx dynamic module_运维_05

五、配置文件解析ngx_conf_parse

配置文件解析的时候,分成三种类型解析:
一种是文件直接一行内容的解析如刚入nginx.conf或include一个文件的时候:parse_file
一种是对形如xxx{}的配置块的解析:parse_block
还有一种就是启动命令参数的解析:parse_param;

1、文件配置token解析ngx_conf_read_token
这个方法按行解析,以分号结束,一行读取,按换行符跳转下一行,以空格为参数分隔符。主要分几种情形:
以分号结束的一行: 每次解析一行结束开始下一行解析时,将cf->args清零,开始单行逐个字符遍历,遇到空格则分割一个关键词,将一行的多个关键词按序push到cf->args中,解析到分号时,结束当前行解析。并返回NGX_OK;如

daemon off;//解析改行后,cf->args有两个元素,分别为daemon,off
text/html  html htm shtml;//解析改行后,cf->args有四个元素,分别为text/html ,html, htm, shtml

以 ‘{’ 结束的一行: 表示进入块配置解析,解析出一个或多个关键词,并返回NGX_CONF_BLOCK_START;如

http {  //解析出关键词http,并push到cf->args,返回NGX_CONF_BLOCK_START状态,表示开启块配置解析;

以 ‘}’ 结束的一行: 表示块配置解析结束,或者文件结束,返回NGX_CONF_BLOCK_DONE,NGX_CONF_FILE_DONE;

一行中存在#: 标记sharp_comment,跳过#后续字符处理

1、core域配置解析

core域配置解析通常是在nginx.conf中的第一级配置中如:daemon off;

disconf nginx配置 nginx dynamic module_apache_06


disconf nginx配置 nginx dynamic module_html_07


disconf nginx配置 nginx dynamic module_disconf nginx配置_08


其他同类型命令的解析流程基本也是如此;2、event域配置解析

先来看看ngx_events_module的基本结构

disconf nginx配置 nginx dynamic module_nginx_09

当解析到events块时:

events {
    worker_connections  1024;
}

先解析到events {,那么在hanlder方法中

disconf nginx配置 nginx dynamic module_html_10

在event域的模块的init_conf会对epoll进行初始化,后面再单独解读event与epoll,本文重点解读配置结构。那么处理到这里,配置的形态如图:

disconf nginx配置 nginx dynamic module_nginx_11

3、http域配置解析

先来看看ngx_http_module的基本结构

disconf nginx配置 nginx dynamic module_运维_12


http的conf_ctx结构比较古怪,采用了分层的结构,分了三层,通过偏移量来找到每层的位置:

//64位系统中指针大小都是8字节,因此每个指针变量偏移量递增8
typedef struct {
    void        **main_conf;//偏移量0
    void        **srv_conf; //偏移量8
    void        **loc_conf; //偏移量16
} ngx_http_conf_ctx_t;

可以看出,基本跟ngx_events_module的结构差不多
当解析到http块时:

http{
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       8081;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

先解析到http{,那么在hanlder方法中

disconf nginx配置 nginx dynamic module_运维_13


在进入http{}的ngx_conf_parse前,会先对每个module进行预配置处理 module->preconfiguration(cf)

比如:ngx_http_core_preconfiguration会将ngx_http_core_variables中的所有配置配置到模块对应的ngx_http_core_main_conf_t配置的variables中。

创建配置后的结构大致如下:(只列出ngx_http_core_module与ngx_http_upstream_module)

disconf nginx配置 nginx dynamic module_html_14


下面来看下http块里的具体细节:

include命令: 导入mime.types命令;

disconf nginx配置 nginx dynamic module_html_15


解析mime.types文件,首先解析types命令

disconf nginx配置 nginx dynamic module_disconf nginx配置_16


disconf nginx配置 nginx dynamic module_nginx_17


mime.types中其他行的处理大致一样。解析server{}块

首先server命令时配置在ngx_http_core_commands中

disconf nginx配置 nginx dynamic module_nginx_18


server命令本身type还是属于ngx_http_main_conf的,进入ngx_http_core_server,开始server命令处理

disconf nginx配置 nginx dynamic module_运维_19


此时http域的配置结构大致如下:

disconf nginx配置 nginx dynamic module_nginx_20

在server{}中会解析监听端口,servername,sendfile等配置,这些配置跟之前的解析差不多;server{}块中,还另外包含了location{}配置块,下面来解读:

location{}配置块解析:

location命令配置在ngx_http_core_commands中

disconf nginx配置 nginx dynamic module_apache_21


下面只解析配置结构相关的内容,location相关URL的处理逻辑可参考NGINX配置说明

server配置location配置

disconf nginx配置 nginx dynamic module_apache_22


location解析完之后的http域配置结构如图:

disconf nginx配置 nginx dynamic module_html_23

这图,相当恶心。到这里,整个配置的解析基本上就完成了。当然很多细节就没在这里关注了,debug的时候看下就行。
当然流程还没走完,回顾下,刚开始进入解析http块,执行完ngx_conf_parse后,还有一部分的后续处理,将留到下一篇继续解读。