您的位置:首页 > 运维架构 > Nginx

nginx源码分析——配置

2016-06-13 23:21 387 查看

1. 配置介绍

nginx的配置由一个主配置文件和其他一些辅助的配置文件构成。这些配置文件均是纯文本文件,这些配置文件全部位于nginx安装目录下的conf目录中。

主配置文件nginx.conf中的内容大概是这样子的:

#user nobody;
worker_processes    1;
pid                 logs/nginx.pid;

events {
worker_connections 1024;
}

http {
include         mime.types;
default_type    application/octet-stream;

sendfile        on;
keepalive_timeout 65;

server {
listen    80;
server_name localhost;

location / {
root    html;
index   index.html index.htm;
}

error_page    500 502 503 504 /50x.html;
location = /50x.html {
root    html;
}
}
}


从上面可以看出:nginx.conf由若干配置项组成,配置项又分为简单配置项和块配置项。

简单配置项由配置项名和配置项值构成。

配置项名是一个字符串,可以用单引号或者双引号括起来,也可以不扩。但是如果配置项名包含空格,则一定要括起来。配置项值使用一个或者多个空格或者TAB与配置项名分开,配置项值可以是数字或者字符串(当然也包括正则表达式)。一个配置项可以有多个配置项值,多个配置项值之间也由空格或者TAB分隔。简单配置项的结尾使用分号结束,其基本的语法格式如下:

配置项名    配置项值1  配置项值2 ... ;


块配置项由一个配置项名和一对大括号组成,其结尾不需要再添加分号。块配置项使用大括号把一系列所属的配置项全部包含起来,表示大括号内的配置项同时生效;块配置项也可以有配置项值,这取决于解析这个配置项的模块;块配置项可以嵌套,内层块直接继承外层块,同一个配置项可以同时出现在内外层块配置项中,其优先级也取决于解析该配置项的模块。

2. 配置解析流程

nginx配置解析的流程基本上是一个递归的过程,如下图所示:



在配置解析的入口函数 ngx_conf_parse 中会循环读取配置文件中的内容,每读取一行后就解析该配置项。解析的过程中可能会再次调用该函数完成后续配置项的解析,例如events块配置项,http块配置项的解析。

对应的源码:

char * ngx_conf_parse(ngx_conf_t * cf, ngx_str_t * filename)
{
...
if( filename ){
fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
...
} else if(cf->conf_file->file.fd != NGX_INVALID_FILE){
type = parse_block;
} else {
type = parse_param;
}

for( ;; ){
rc = ngx_conf_read_token(cf);

if(cf->handler){
...
}

rc = ngx_conf_handler(cf, rc);
}
...
}

static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
{
for(i = 0; cf->cycle->modules[i]; i++){
cmd = cf->cycle->modules[i]->commands;
if(cmd == NULL){
continue;
}

for( ; cmd->name.len; cmd++ ){
if( name->len != cmd->name.len){
continue;
}
if(ngx_strcmp(name->data, cmd->name.data) != 0){
continue;
}
found = 1;
...
rc = cmd->set(cf, cmd, conf);
}
}
}


ngx_conf_parse函数支持三种不同的解析环境:

parse_file:解析配置文件

parse_block: 解析块配置项

parse_param:解析命令行配置。(注:命令行配置不支持块配置项)

从前面的解析流程可以看出,首次调用ngx_conf_parse进行配置解析时,类型为parse_file,当递归调用时,ngx_conf_parse的filename参数均设置为空,即正在进行块配置项的解析,例如:

static char * ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
...
cf->ctx = ctx;
cf->module_type = NGX_EVENT_MODULE;
cf->cmd_type = NGX_EVENT_CONF;

rv = ngx_conf_parse(cf, NULL);
...
}


在ngx_conf_handler的校验过程中会针对模块类型、配置项类型、配置项值个数等进行校验。

模块类型:校验配置项所属的模块是否为当前处理配置项解析的模块。

if( cf->cycle->modules[i]->type != NGX_CONF_MODULE &&
cf->cycle->modules[i]->type != cf->module_type ){
continue;
}

cf->module_type 初始值设置为 NGX_CORE_MODULE(在ngx_init_cycle函数中初始化),解析到配置项 http { 的时候,找到ngx_http_module模块,并调用ngx_http_block处理该配置项。从ngx_http_module模块的定义可以看到其类型确实为NGX_CORE_MODULE。

static ngx_command_t ngx_http_commands[] = {
{ ngx_string("http"),
NGX_MAIN_CONF | NGX_CONF_BLOCK | NGX_CONF_NOARGS,
ngx_http_block,
0,
0,
NULL
},
ngx_null_command
};

ngx_module_t ngx_http_module = {
NGX_MODULE_V1,
&ngx_http_module_ctx,
ngx_http_commands,
NGX_CORE_MODULE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_P1_PADDING
};

在ngx_http_block中将cf->module_type设置为NGX_HTTP_MODULE,解析http块配置项中的其他配置项时,找到对应的http模块并进行后续处理,而所有http模块的类型均定义为NGX_HTTP_MODULE。 这样,可有效防止配置项被其他模块所处理。

配置项类型:与模块类型类似

if(!(cmd->type & cf->cmd_type)){
continue;
}

cmd->type初始值为NGX_MAIN_CONF,前面提到的ngx_http_module模块的配置项数组中http配置项的类型包含了NGX_MAIN_CONF。

配置项值的个数

前面提到每个配置项名后可以有多个配置项值,当前配置项值的最大个数定义为8。代码中有相关的宏对应。配置项值的个数必须正确才能进行实际的配置项解析。

#define  NGX_CONF_MAX_ARGS  8
#define  NGX_CONF_NOARGS    0x00000001  //无配置项值
#define  NGX_CONF_TAKE1     0x00000002  //接受1个配置项值
#define  NGX_CONF_TAKE2     0x00000004  //接受2个配置项值
#define  NGX_CONF_TAKE3     0x00000008  //接受3个配置项值
#define  NGX_CONF_TAKE4     0x00000010  //接受4个配置项值
#define  NGX_CONF_TAKE5     0x00000020  //接受5个配置项值
#define  NGX_CONF_TAKE6     0x00000040  //接受6个配置项值
#define  NGX_CONF_TAKE7     0x00000080  //接受7个配置项值
#define  NGX_CONF_BLOCK     0x00000100  //接受块配置项
#define  NGX_CONF_FLAG      0x00000200  //接受配置项值为on或者off
#define  NGX_CONF_ANY       0x00000400  //接受任意的配置项值
#define  NGX_CONF_1MORE     0x00000800  //至少1个配置项值
#define  NGX_CONF_2MORE     0x00001000  //至少2个配置项值
#define  NGX_CONF_MULTI     0x00000000  //接受多个配置项值 个数不定

//接受1个或2个配置项值
#define NGX_CONF_TAKE12     (NGX_CONF_TAKE1|NGX_CONF_TAKE2)
//接受1个或3个配置项值
#define NGX_CONF_TAKE13     (NGX_CONF_TAKE1|NGX_CONF_TAKE3)
//接受2个或3个配置项值
#define NGX_CONF_TAKE23     (NGX_CONF_TAKE2|NGX_CONF_TAKE2)
//接受1个或2个或3个配置项值
#define NGX_CONF_TAKE123    (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3)
//接受1个或2个或4个配置项值
#define NGX_CONF_TAKE1234   (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3|NGX_CONF_TAKE4)


参考:

《深入理解nginx》

《nginx开发从入门到精通》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: