菜鸟学习nginx之模块定义

今天开始介绍Nginx框架相关内容。

Nginx将所有功能进行模块化区分,按照功能统一编排,例如:事件模块,HTTP模块,邮箱模块,配置文件模块等。对于复杂模块,又支持子模块定义,例如HTTP模块中有ngx_http_header_filter_module等。Nginx为这些模块都进行统一的封装,保证接口的统一化。接下来我们来学习一下Nginx优良设计。

一、Nginx架构

我们先来看一下,Nginx整体框架,可能理解不是清晰,如有不对请大家留言,虚心接受指点。

说明:

  1. Nginx功能强大之一体现在可定制化。Nginx配置文件非常强大,对于一般需求,只需要修改配置文件即可满足。而Nginx中ngx_conf_module模块又是基础模块。
  2. Nginx定义了一些核心模块(ngx_module_t中type为NGX_CORE_MODULE),我将定义为抽象层。各个抽象层中模块,会定义出具体接口。例如HTTP模块所具有的特征以及行为。上图出所有橙色模块都是核心模块。
  3. 实现层主要定义各个模块具体行为,例如http模块报文解析,访问权限等。
  4. 由于篇幅问题,在上图中只画出事件模块和http模块

这里可以用一个形象的比喻来描述Nginx框架:绿色相当于学校的场地,教学楼等属于基础设施,橙色相当于校长,教导主任等上层管理者,蓝色相当于班主任,负责每个班级的管理,紫色相当于学生。

二、模块定义

 Nginx中万物皆模块,当我们为了新的业务需求时需要定制开发,我们必须定义成一个module。下面是Nginx中module结构体定义,如下:

struct ngx_module_s {
    /**
     * 每个模块又可以存在子模块,例如: ngx_event_core_module, ngx_epoll_module
     * 都是从属于ngx_events_module模块的子模块。
     * ctx_index初始化在函数ngx_count_modules中
     */
    ngx_uint_t            ctx_index;
    /**
     * 数组下标 在configure过程中生成文件ngx_modules.c 里面有一个数组ngx_modules
     * 其index就是ngx_modules数组下标. index初始化ngx_module_index
     */
    ngx_uint_t            index;

    char                 *name; //模块名称

    ngx_uint_t            spare0;
    ngx_uint_t            spare1;

    ngx_uint_t            version;
    const char           *signature;
    
    /** 模块定义时指定
     * 不同模块实际指向不同,例如:
     * NGX_CORE_MODULE 指向的结构体ngx_core_module_t
     * NGX_EVENT_MODULE 指向的结构体ngx_event_module_t
     * NGX_HTTP_MODULE 指向的结构体ngx_http_module_t
     */
    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_init_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;
};

字段名称

含义

备注

ctx_index

当前module在子类型下索引值

Nginx支持子类型。例如Nginx定义了很多NGX_HTTP_MODULE (http模块),那么这些module需要指定在HTTP模块下面索引,就是用ctx_index表示。

index

当前module在全局数组ngx_modules下标

Module在全局数组ngx_modules中下标值

name

模块名称

 

spare0 ~ spare1

预留

 

version

版本号

 

signature

签名

 

ctx

当前模块上下文

模块在定义时需要指定ctx值,相同模块类型,指向的上下文是相同的。

commands

配置文件解析

用于解析配置文件,例如出现某个标签,需要调用对应的解析函数。该变量在模块定义时指定

type

当前模块类型

 

init_master

没有使用

 

init_module

初始化模块

在函数ngx_init_cycle中调用

init_process

模块定义的worker进程初始化

在函数ngx_worker_process_init中调用

init_thread

没有使用

 

exit_thread

没有使用

 

exit_process

进程退出

在函数ngx_worker_process_exit中调用

exit_master

master进程退出

在函数ngx_master_process_exit中调用

spare_hook0 ~spare_hook1

预留

 

说明:

目前Nginx内置模块类型(type)有:NGX_CONF_MODULE,NGX_CORE_MODULE,NGX_EVENT_MODULE,NGX_HTTP_MODULE,NGX_MAIL_MODULE,NGX_STREAM_MODULE 

下面以ngx_events_module举例说明,以此来感知定义方式:

/** 
* 解析命令字 即解析配置文件 当配置文件出现标签events时调用ngx_events_block方法 
*/
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_core_module_t作为上下文
*/
static ngx_core_module_t ngx_events_module_ctx = {
    ngx_string("events"),
    NULL,
    ngx_event_init_conf};
/**
 * 模块定义--事件模块
*/
ngx_module_t ngx_events_module = {
    NGX_MODULE_V1,
    &ngx_events_module_ctx, /* module context 模块上下 ctx*/
    ngx_events_commands,    /* module directives */
    NGX_CORE_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
};

三、模块初始化

在介绍启动流程时,已经比较详细介绍过关于模块的初始化。简单回顾一下。

首先,Nginx将所有模块都统一到ngx_modules数组中,该数组是在configure过程中生成,数组定义在ngx_modules.c文件中,如下:

ngx_module_t *ngx_modules[] = {
    &ngx_core_module,
    &ngx_errlog_module,
    &ngx_conf_module,
    &ngx_regex_module,
    &ngx_events_module,
    &ngx_event_core_module,
    &ngx_epoll_module,
    &ngx_http_module,
    &ngx_http_core_module,
    ...
}

其中ngx_module_t结构体中index就是该数组下标。Nginx在管理模块索引时采用的就是数组下标,所以我们不能轻易修改下标值。

ctx_index所以也是基于下标,但是下标不是和index一样。先划分模块类型(type)进行类别分类,最后在统一编排。

/**
 * 获取相同类型下module数量
 * @param cycle 核心结构体
 * @param type  模块类型 例如NGX_EVENT_MODULE,NGX_HTTP_MODULE
 * @return 返回数量
 * 注意此方法,还会设置子类型索引 即在相同module类型下ctx_index
 */
ngx_int_t
ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type)

 其次,调用init_module回调函数,用于初始化模块。例如核心模块ngx_event_core_module中ngx_event_module_init,初始化共享内存等。

再次,在worker进程创建之后调用init_process回调函数,初始化服务相关。例如:监听端口添加到事件驱动中。

对于事件模块后续有专题介绍

四、总结

本篇主要介绍的内容是,如何定义一个module以及module中重要成员。因为Nginx中所有功能模块都是module进行划分,如果对于module使用以及定义仍然不清楚的,可参考我之前写的《菜鸟学习Nginx之入门开发留言板》,下一篇介绍Nginx事件驱动

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值