美文网首页
Nginx源码学习——配置项生效的大体流程

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

作者: 丹丘生___ | 来源:发表于2019-06-29 20:59 被阅读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的值决定了连接、读写事件的数量。

    相关文章

      网友评论

          本文标题:Nginx源码学习——配置项生效的大体流程

          本文链接:https://www.haomeiwen.com/subject/huunnftx.html