Nginx模块的配置与解析

1. 模块的定义

struct ngx_module_s {
    ngx_uint_t            ctx_index;
    ngx_uint_t            index;

    ngx_uint_t            spare0;
    ngx_uint_t            spare1;
    ngx_uint_t            spare2;
    ngx_uint_t            spare3;

    ngx_uint_t            version;

    void                 *ctx;
    ngx_command_t        *commands;
    ngx_uint_t            type;

    ngx_int_t           (*init_master)(ngx_log_t *log);

    ngx_int_t           (*init_module)(ngx_cycle_t *cycle);

    ngx_int_t           (*init_process)(ngx_cycle_t *cycle);
    ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);
    void                (*exit_thread)(ngx_cycle_t *cycle);
    void                (*exit_process)(ngx_cycle_t *cycle);

    void                (*exit_master)(ngx_cycle_t *cycle);

    uintptr_t             spare_hook0;
    uintptr_t             spare_hook1;
    uintptr_t             spare_hook2;
    uintptr_t             spare_hook3;
    uintptr_t             spare_hook4;
    uintptr_t             spare_hook5;
    uintptr_t             spare_hook6;
    uintptr_t             spare_hook7;
};
模块实例:

ngx_module_t  ngx_epoll_module = {
    NGX_MODULE_V1,
    &ngx_epoll_module_ctx,               /* module context */
    ngx_epoll_commands,                  /* module directives */
    NGX_EVENT_MODULE,                    /* module type */
    NULL,                                /* init master */
    NULL,                                /* init module */
    NULL,                                /* init process */
    NULL,                                /* init thread */
    NULL,                                /* exit thread */
    NULL,                                /* exit process */
    NULL,                                /* exit master */
    NGX_MODULE_V1_PADDING
};
2. 模块上下文类型

typedef struct {
    ngx_str_t             name;
    void               *(*create_conf)(ngx_cycle_t *cycle);
    char               *(*init_conf)(ngx_cycle_t *cycle, void *conf);
} ngx_core_module_t;
typedef struct {
    ngx_str_t              *name;

    void                 *(*create_conf)(ngx_cycle_t *cycle);
    char                 *(*init_conf)(ngx_cycle_t *cycle, void *conf);

    ngx_event_actions_t     actions;
} ngx_event_module_t;
typedef struct {
    ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);
    ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);

    void       *(*create_main_conf)(ngx_conf_t *cf);
    char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);

    void       *(*create_srv_conf)(ngx_conf_t *cf);
    char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);

    void       *(*create_loc_conf)(ngx_conf_t *cf);
    char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_http_module_t;
模块上下文实例:

ngx_event_module_t  ngx_epoll_module_ctx = {
    &epoll_name,
    ngx_epoll_create_conf,               /* create configuration */
    ngx_epoll_init_conf,                 /* init configuration */

    {
        ngx_epoll_add_event,             /* add an event */
        ngx_epoll_del_event,             /* delete an event */
        ngx_epoll_add_event,             /* enable an event */
        ngx_epoll_del_event,             /* disable an event */
        ngx_epoll_add_connection,        /* add an connection */
        ngx_epoll_del_connection,        /* delete an connection */
        NULL,                            /* process the changes */
        ngx_epoll_process_events,        /* process the events */
        ngx_epoll_init,                  /* init the events */
        ngx_epoll_done,                  /* done the events */
    }
};
2. 模块的配置解析
模块的解析在nginx.c的函数ngx_init_cycle中

ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
{
   ...

   // 为核心模块创建配置
   for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->type != NGX_CORE_MODULE) {
            continue;
        }

        module = ngx_modules[i]->ctx;

        if (module->create_conf) {
            rv = module->create_conf(cycle);
            if (rv == NGX_CONF_ERROR) {
                ngx_destroy_pool(pool);
                return NULL;
            }
            cycle->conf_ctx[ngx_modules[i]->index] = rv;
        }
    }
    ...
    if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
        ngx_destroy_cycle_pools(&conf);
        return NULL;
    }

    // 为核心模块初始化配置
    for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->type != NGX_CORE_MODULE) {
            continue;
        }

        module = ngx_modules[i]->ctx;

        if (module->init_conf) {
            if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index])
                == NGX_CONF_ERROR)
            {
                ngx_destroy_cycle_pools(&conf);
                return NULL;
            }
        }
    }
    ...
}
非核心模块的配置解析嵌套在核心模块的配置初始化过程中,例如对于事件核心模块ngx_events_module,其配置指令结构定义为:

static ngx_command_t  ngx_events_commands[] = {

    { ngx_string("events"),
      NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
      ngx_events_block,
      0,
      0,
      NULL },

      ngx_null_command
};
也就是说事件核心模块的配置解析是从函数ngx_events_block开始,在函数内部实现了事件核心模块的所有下属子模块(事件模块)配置的创建和初始化:

static char *
ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ...

    // 为事件模块创建配置
    for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->type != NGX_EVENT_MODULE) {
            continue;
        }

        m = ngx_modules[i]->ctx;

        if (m->create_conf) {
            (*ctx)[ngx_modules[i]->ctx_index] = m->create_conf(cf->cycle);
            if ((*ctx)[ngx_modules[i]->ctx_index] == NULL) {
                return NGX_CONF_ERROR;
            }
        }
    }
    ....

    // 为事件模块初始化配置
    for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->type != NGX_EVENT_MODULE) {
            continue;
        }

        m = ngx_modules[i]->ctx;

        if (m->init_conf) {
            rv = m->init_conf(cf->cycle, (*ctx)[ngx_modules[i]->ctx_index]);
            if (rv != NGX_CONF_OK) {
                return rv;
            }
        }
    }
}
其余比如HTTP模块或者Mail模块的配置加载和初始化过程与此相同。
3. 模块的初始化
根据模块的定义结构可以知道,在Nginx启动的不同阶段都会对模块进行初始化,分别为:
init_master 初始化主进程时
init_module 初始化模块时
init_process 初始化子进程时
init_thread  初始化子线程时
在函数ngx_init_cycle的最后会调用每一个模块的初始化函数init_module:

ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
{
    ...
    for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->init_module) {
            if (ngx_modules[i]->init_module(cycle) != NGX_OK) {
                /* fatal */
                exit(1);
            }
        }
    }
    ...
}
在进程的初始化函数中会调用init_process:

static void
ngx_worker_process_init(ngx_cycle_t *cycle, ngx_uint_t priority)
{
    ...
    for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->init_process) {
            if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
                /* fatal */
                exit(2);
            }
        }
    }
    ...
}
例如在模块ngx_event_core_module的init_process函数ngx_event_process_init中会调用所有事件模块的actions.init函数,

static ngx_int_t
ngx_event_process_init(ngx_cycle_t *cycle)
{
    ...
    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_EVENT_MODULE) {
            continue;
        }

        if (ngx_modules[m]->ctx_index == ecf->use) {
            module = ngx_modules[m]->ctx;
            if (module->actions.init(cycle, ngx_timer_resolution) == NGX_ERROR)
            {
                /* fatal */
                exit(2);
            }
            break;
        }
    }
    ...
}
对于采用EPOLL模型的ngx_epoll_module模块而言,就是eventpoll数据结构的创建以及初始化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
nginx是一个高性能的Web服务器,同时也是一个反向代理服务器和电子邮件(IMAP/POP3)代理服务器。它最显著的特点是具有高并发处理能力和低内存占用。为了满足不同用户的需求,nginx提供了模块化的架构,可以通过开发模块来扩展其功能。 深入理解nginx模块开发,首先需要了解nginx的架构。nginx的主要部分包括master进程和worker进程。master进程负责管理worker进程,而worker进程负责处理实际的客户端请求。nginx模块系统允许开发者向master进程或worker进程添加自定义的功能。 在nginx模块开发中,主要涉及到以下几个方面的内容: 1. 配置文件解析nginx配置文件是使用类似于C语言的语法进行解析的。模块开发者需要了解nginx配置文件语法,并且能够解析和处理自定义的配置项。 2. HTTP请求处理:开发基于HTTP协议的模块时,需要能够处理和解析HTTP请求。模块可以拦截特定的URL,处理请求,并返回相应的响应。 3. 事件处理:nginx使用事件驱动的模型来处理并发请求。模块开发者需要了解事件驱动的机制,实现自己的事件处理逻辑,并与nginx的事件处理系统进行交互。 4. 内存管理:nginx以低内存占用著称,这是因为它使用了自己的内存管理机制。模块开发者需要了解nginx的内存管理方式,并遵循相应的规则。 5. 日志记录:nginx提供了灵活的日志记录功能。模块开发者可以通过定制日志记录方式,将特定的信息记录到指定的日志文件中。 总的来说,深入理解nginx模块开发与架构解析需要对nginx的整体架构有深入了解,并具备一定的系统编程和网络编程经验。通过开发和调试模块,可以进一步理解nginx的原理和内部实现,掌握更多高性能Web服务器开发的知识和技巧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值