Nginx源码学习——配置项生效的大体流程

2019-06-29  本文已影响0人  丹丘生___

摘要:Nginx服务在启动时就会读取配置文件,配置文件影响着服务的工作方式、性能优化等诸多方面,我们以core和event模块为例,看看在Nginx服务的启动过程中,配置项是怎么一步步从被读取到最终生效的。


配置文件路径

一般来说,配置文件名为:nginx.conf. 保存在/usr/local/nginx/conf, /etc/nginx, 或 /usr/local/etc/nginx.
也可以由用户指定路径,通过命令行传递给进程,如:nginx -c ./nginx.conf

Nginx服务启动后,main() 通过解析命令行参数、获取当前可执行文件目录等操作,最终取得了完整的nginx.conf配置文件路径。


解析配置文件并存储配置参数

main()执行初始化过程中,调用ngx_init_cycle函数,该函数是nginx启动过程中非常重要的一环。
它负责许多重要的初始化工作,其中与配置相关的可分为三步:

  1. 调用所有核心模块的create_conf方法,生成存放配置项的结构体。
  2. 针对所有核心模块解析nginx.conf配置文件。
  3. 解析配置文件完成后,调用所有核心模块的init_conf方法,初始化各核心模块配置项结构体。

我们重点来说第1步和第3步,第2步解析过程也有许多细节,但这里我们不在详述。

回调各个核心模块的create_conf函数:

 //遍历模块数组,找到核心模块,获得核心模块的上下文结构体指针ctx,使用该指针调用回调函数create_conf
 //以获取一块内存保存配置项数据结构,返回指向该内存的指针,根据模块索引保存指针到conf_ctx数组中
    for (i = 0; cycle->modules[i]; i++) {
        if (cycle->modules[i]->type != NGX_CORE_MODULE) {
            continue;
        }

        module = cycle->modules[i]->ctx;

        if (module->create_conf) {
            rv = module->create_conf(cycle);
            if (rv == NULL) {
                ngx_destroy_pool(pool);
                return NULL;
            }
            cycle->conf_ctx[cycle->modules[i]->index] = rv;
        }
    }

解析配置文件完成后,回调各核心模块的的init_conf函数,初始化各模块配置项结构体:

    //解析配置项完成后,遍历模块数组,找到核心模块,获得核心模块的上下文结构体指针ctx,
    //使用该指针调用回调函数init_conf,同时,根据模块索引从conf_ctx数组中获取指向存储配置项
    //的结构体变量的指针,将该指针作为参数之一传入init_conf函数
    for (i = 0; cycle->modules[i]; i++) {
        if (cycle->modules[i]->type != NGX_CORE_MODULE) {
            continue;
        }

        module = cycle->modules[i]->ctx;

        if (module->init_conf) {
            if (module->init_conf(cycle,
                                  cycle->conf_ctx[cycle->modules[i]->index])
                == NGX_CONF_ERROR)
            {
                environ = senv;
                ngx_destroy_cycle_pools(&conf);
                return NULL;
            }
        }
    }

Nginx源码学习——从数据结构看模块划分 一文中可知create_conf和init_conf回调函数是如何能够工作的,以及模块间的层次关系。

对于core模块来说,有这样一个模块上下文(module context)结构体:

static ngx_core_module_t  ngx_core_module_ctx = {
    ngx_string("core"),
    ngx_core_module_create_conf,//创建存储配置项的数据结构
    ngx_core_module_init_conf; // 初始化配置项数据结构
};

ngx_core_module_create_conf就是ngx_init_cycle函数内回调的core模块的create_conf函数。
ngx_core_module_init_conf就是ngx_init_cycle函数内回调的core模块的init_conf函数。

同理,对于event模块,其通用接口ngx_event_module_t 定义的上下文结构体(module context)变量:

static ngx_event_module_t  ngx_event_core_module_ctx = {
    &event_core_name,
    ngx_event_core_create_conf,            /* create configuration */
    ngx_event_core_init_conf,              /* init configuration */

    { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};

ngx_event_core_create_conf函数就是ngx_init_cycle函数内回调的event模块的create_conf函数。
ngx_event_core_init_conf函数就是ngx_init_cycle函数内回调的event模块的init_conf函数。


配置项生效

启动worker进程后,将调用函数ngx_worker_process_init,内部回调所有模块的init_process函数,代码片段:

    for (i = 0; cycle->modules[i]; i++) {
        if (cycle->modules[i]->init_process) {
            if (cycle->modules[i]->init_process(cycle) == NGX_ERROR) {
                /* fatal */
                exit(2);
            }
        }
    }

拿event模块举例,init_process函数是定义ngx_module_t结构体ngx_event_core_module时注册的:

ngx_module_t  ngx_event_core_module = {
    NGX_MODULE_V1,
    &ngx_event_core_module_ctx,            /* module context */
    ngx_event_core_commands,               /* module directives */
    NGX_EVENT_MODULE,                      /* module type */
    NULL,                                  /* init master */
    ngx_event_module_init,                 /* init module */
    ngx_event_process_init,                /* init process */
    NULL,                                  /* init thread */
    NULL,                                  /* exit thread */
    NULL,                                  /* exit process */
    NULL,                                  /* exit master */
    NGX_MODULE_V1_PADDING
};

即回调init_process时,执行的是ngx_event_process_init函数。
下面具体看看配置项是如何起作用的,比如worker_connections配置项,将根据该配置项的值决定创建多少连接、读事件和写事件。代码如下所示:

    cycle->connections =
        ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log);
    if (cycle->connections == NULL) {
        return NGX_ERROR;
    }

    c = cycle->connections;

    cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
                                   cycle->log);
    if (cycle->read_events == NULL) {
        return NGX_ERROR;
    }

    rev = cycle->read_events;
    for (i = 0; i < cycle->connection_n; i++) {
        rev[i].closed = 1;
        rev[i].instance = 1;
    }

    cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
                                    cycle->log);
    if (cycle->write_events == NULL) {
        return NGX_ERROR;
    }

    wev = cycle->write_events;
    for (i = 0; i < cycle->connection_n; i++) {
        wev[i].closed = 1;
    }

cycle->connection_n 即是worker_connections配置项的值。可见,connection_n的值决定了连接、读写事件的数量。

上一篇下一篇

猜你喜欢

热点阅读