在NGINX的启动流程中,ngx_init_cycle是重点之一,而在ngx_init_cycle中,配置文件的解析又是重点中的重点。本文重点记录core域,event域,http域配置加载逻辑,主要记录个人重点关注的部分。
一、配置文件结构(命令类型)
配置文件每行(非注释行)的首个单词,当做是一个指令command(cmd);单行配置以分号为一行结束,以{}表示一个配置块,一个块中可以嵌套其他的块。
二、module基本静态配置
本文暂不做动态添加模块的相关笔记,NGINX初始提供一个默认的静态module数组,里面包含core域,events域,http域的默认模块列表。objs/ngx_modules.c
每个模块都用extern修饰,说明是引用的全局变量,比如ngx_core_module(nginx.c中定义):
基本每个模块都采用这种方式的配置,不同的是各种方法指针和配置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行
此时的配置结构如下:
五、配置文件解析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;
其他同类型命令的解析流程基本也是如此;2、event域配置解析
先来看看ngx_events_module的基本结构
当解析到events块时:
events {
worker_connections 1024;
}
先解析到events {
,那么在hanlder方法中
在event域的模块的init_conf会对epoll进行初始化,后面再单独解读event与epoll,本文重点解读配置结构。那么处理到这里,配置的形态如图:
3、http域配置解析
先来看看ngx_http_module的基本结构
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方法中
在进入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)
下面来看下http块里的具体细节:
include命令: 导入mime.types命令;
解析mime.types文件,首先解析types命令
mime.types中其他行的处理大致一样。解析server{}块
首先server命令时配置在ngx_http_core_commands中
server命令本身type还是属于ngx_http_main_conf的,进入ngx_http_core_server,开始server命令处理
此时http域的配置结构大致如下:
在server{}中会解析监听端口,servername,sendfile等配置,这些配置跟之前的解析差不多;server{}块中,还另外包含了location{}配置块,下面来解读:
location{}配置块解析:
location命令配置在ngx_http_core_commands中
下面只解析配置结构相关的内容,location相关URL的处理逻辑可参考NGINX配置说明
location解析完之后的http域配置结构如图:
这图,相当恶心。到这里,整个配置的解析基本上就完成了。当然很多细节就没在这里关注了,debug的时候看下就行。
当然流程还没走完,回顾下,刚开始进入解析http块,执行完ngx_conf_parse后,还有一部分的后续处理,将留到下一篇继续解读。