文档章节

nginx源码分析——模块

hncscwc
 hncscwc
发布于 2016/06/17 15:21
字数 1618
阅读 176
收藏 2

1. 模块介绍

高度模块化的设计是nginx的架构基础。在nginx中,除了少量的核心代码,其他一切皆为模块。这种模块化设计同时具有以下几个特点:

  • 高度抽象的模块接口

    所有的模块都遵循着同样的 ngx_module_t 接口设计规范,这减少了整个系统中的变数。

  • 模块接口非常简单,具有很高的灵活性

    模块的基本接口 ngx_module_t 足够简单,只涉及模块的初始化、退出以及对配置项的处理、这同时也带来了足够的灵活性,使得nginx比较简单地实现了动态可修改性。

  • 配置模块的设计

    ngx_module_t接口有一个type成员,它指明了nginx允许在设计模块时定义模块类型这个概念,允许专注于不同领域的模块按照类型来区别。而配置类型模块是唯一一种只有1个模块的模块类型。配置模块的类型叫做NGX_CONF_MODULE,它仅有的模块叫做ngx_conf_module。这是nginx最底层的模块,它指导着所有模块以配置项为核心来提供功能。因此,它是其他所有模块的基础。配置模块使nginx提供了高可配置性,高可扩展性,高可定制性,高可伸缩性。

  • 核心模块接口的简单化

    nginx中定义了一种基础类型的模块——核心模块。核心模块的存在简化了nginx的设计,使得非模块化的框架代码只关注于如何调用这些核心模块。

  • 多层次、多类别的模块设计

    所有的模块间是分层次的,分类别的。不同的模块虽然都具备相同的ngx_module_t接口,单在请求处理流程中的层次并不相同。nginx将各功能组织成一条链,当有请求到达的时候,请求依次经过这条链上的部分或者全部模块进行处理。

2. 模块的分类

nginx模块分为核心模块和功能性模块,功能性模块包括conf、event、http、mail、stream几大类。除了conf类以外,其他几类功能性模块都包含众多的模块,并且每个类别中都有一个核心模块。其主要作用是提供本类别功能通用的框架接口,逻辑处理等,并调用同类型的其他模块完成具体的功能。例如NGX_HTTP_MODULE类别中的核心模块ngx_http_core_module,负责http块配置项中通用的配置解析、http请求处理的整体流程,并调用其他NGX_HTTP_MODULE模块完成具体的处理。

nginx中常用模块分层分类:


3. 模块的相关结构体

  • ngx_module_t接口
struct ngx_module_s {
    ngx_uint_t      ctx_index;                           // 模块在同类型模块数组中的索引序号
    ngx_uint_t      index;                               // 模块在所有模块数组中的索引序号
    char *          name;                                // 模块的名称
    ngx_uint_t      spare0;                              // 保留变量
    ngx_uint_t      spare1;                              // 保留变量
    ngx_uint_t      version;                             // 模块的版本号 目前只有一种,默认为1
    const char*     signature;
    void *          ctx;                                 // 模块上下文结构体 不同的模块指向不同的结构体
    ngx_command_t * commands;                            // 模块关心的配置项表 配置文件解析时会查找该表
    ngx_uint_t      type;                                // 模块类型 如NGX_CORE_MODULE
    ngx_int_t       (*init_master)(ngx_log_t *log);      // master进程启动时回调
    ngx_int_t       (*init_module)(ngx_cycle *cycle);    // 初始化模块时回调
    ngx_int_t       (*init_process)(ngx_cycle_t *cycle); // worker进程启动时回调
    ngx_int_t       (*init_thread)(ngx_cycle_t *cycle);  // 线程启动时回调(nginx暂时无多线程模式)
    void            (*exit_thread)(ngx_cycle_t *cycle);  // 线程退出时回调
    void            (*exit_process)(ngx_cycle_t *cycle); // worker进程退出时回调
    void            (*exit_master)(ngx_cycle_t *cycle);  // master进程退出时回调
    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;
};

typedef struct ngx_module_s  ngx_module_t;
  • 配置项
struct ngx_command_s {
    // 配置项的名称
    ngx_str_t    name;
    // 配置项的类型
    ngx_uint_t   type;
    // 配置项解析处理函数
    char *       (*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
    // 用于指示配置项所处内存的相对偏移位置
    ngx_uint_t   conf;
    // 表示当前配置项在整个存储配置项的结构体中的偏移位置
    ngx_uint_t   offset;
    // 配置项读取后的处理方法 必须是ngx_conf_post_t结构体的指针
    void *       post;
};

typedef struct ngx_command_s  ngx_command_t;
  • 核心模块类型的上下文
typedef struct {
    // 模块的名称 例如 core, http, mail
    ngx_str_t    name;
    // 分配内存(创建相关结构体)用于存储配置项解析时配置项值的存储
    void *       (*create_conf)(ngx_cycle_t *cycle);
    // 初始化配置项的初始值
    char *       (*init_conf)(ngx_cycle_t *cycle, void *conf);
} ngx_core_module_t ;

4. 模块初始化流程

  • 编译生成ngx_modules.c

    执行configure后,会在objs目录下生成nginx_modules.c源文件。这个源文件中有两个很重要的全局变量ngx_modules和ngx_module_names,前者保存了nginx将要使用的全部模块,后者则记录了这些模块的名称。

ngx_module_t *ngx_modules[] = {
    &ngx_core_module,
    &ngx_errlog_module,
    &ngx_conf_module,
    &ngx_openssl_module,
    &ngx_regex_module,
    &ngx_events_module,
    &ngx_event_core_module,
    ...
};

char *ngx_module_names[] = {
    "ngx_core_module"
    "ngx_errlog_module",
    "ngx_conf_module",
    "ngx_openssl_module",
    "ngx_regex_module",
    "ngx_events_module",
    "ngx_event_core_module",
    ...
};
  • 预初始化

    初始化每个模块的索引以及名称。

ngx_int_t  ngx_preinit_modules(void)
{
    ngx_uint_t  i;
    for( i = 0; ngx_modules[i]; i++ )
    {
        ngx_modules[i]->index = i;
        ngx_modules[i]->name = ngx_module_names[i];
    }

    ngx_modules_n = i;
    ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES;

    return NGX_OK;
}
  • 针对核心模块创建配置解析时需要的上下文
ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle)
{
    ...
    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;
        }
    }
    ...
}
  • 查找模块的配置项表并调用对应处理函数完成配置文件解析
  • 初始化核心模块的配置
​ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle)
{
    ...
    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;
            }
        }
    }
    ...
}
  • 初始化各个模块
ngx_int_t ngx_init_modules(ngx_cycle_t * cycle)
{
    ngx_uint_t i;
    // 目前只有三个模块该函数指针非空
    // 分别是 event_core, http_v2, regex
    for( i = 0; cycle->modules[i]; i++ ) {
        if(cycle->modules[i]->init_module) {
            if(cycle->modules[i]->init_module(cycle) != NGX_OK) {
                return NGX_ERROR;
            }
        }
    }
    return NGX_OK;
}
  • 调用模块的进程启动初始化回调函数
// init_master 回调函数当前没有使用 即每个模块都设置为NULL
// init_process 回调函数当前有event_core, http_userid_filter, thread_pool模块进行设置
for( i = 0 ; cycle->modules[i]; i++ ) {
    if( cycle->modules[i]->init_process ) {
        if( cycle->modules[i]->init_process(cycle) == NGX_ERROR ) {
            exit(2);
        }
    }
}

到此模块初始化流程结束,master/worker进程开始各自的循环。


参考:

《深入理解nginx》

《nginx开发从入门到精通》

© 著作权归作者所有

hncscwc
粉丝 66
博文 70
码字总数 76137
作品 0
杭州
程序员
私信 提问
nginx源码分析—启动流程

作者:阿波 本文链接: http://blog.csdn.net/livelylittlefish/article/details/7243718 Content 0. 序 1. main()分析 2. 注意问题 2.1 几个初值 2.2 nginx工作模式 2.3 一些配置 2.4 其他开...

晨曦之光
2012/03/09
1K
0
nginx源码分析—hash结构ngx_hash_t(v1.0.4)

本博客(http://blog.csdn.net/livelylittlefish )贴出作者(阿波)相关研究、学习内容所做的笔记,欢迎广大朋友指正! Content 0.序 1.hash结构 1.1ngx_hash_t结构 1.2ngx_hash_init_t结构...

晨曦之光
2012/03/09
757
0
nginx 源码调试

这段时间正在学习nginx源码,看到一贴子的提问 (帖子:http://www.oschina.net/question/27119912165566?p=1#AnchorAnswer1114315),决定试试能不能搞定。 这个帖子的主要问题是,自己写的...

悬崖
2016/04/14
264
1
nginx源码分析—队列结构ngx_queue_t

本博客(http://blog.csdn.net/livelylittlefish )贴出作者(阿波)相关研究、学习内容所做的笔记,欢迎广大朋友指正! Content 0. 序 1. 队列结构 2. 队列操作 2.1 在头节点之后插入 2.2 ...

晨曦之光
2012/03/09
238
2
【NGINX】nginx安装(基于ubuntu)

模块依赖性 gzip 模块需要 zlib 库 rewrite 模块需要 pcre 库 ssl 功能需要 openssl 库 预先编译好的安装包 Nginx在一些Linux发行版和BSD的各个变种版本的安装包仓库中都会有,通过各个系统自...

晨曦之光
2012/03/01
907
0

没有更多内容

加载失败,请刷新页面

加载更多

Rust 的 GUI 框架生态概览

本文比较全面比较了目前主流的 Rust 的 GUI 框架的表现。其中 ++ 表示非常好,-- 表示非常差,而 o 表示处于平均水平。 参与对比的框架共有 8 个,详细的比较结果如下: Electron + Neon El...

红薯
12分钟前
3
0
golang微服务框架go-micro 入门笔记2.1 micro工具之micro api

micro api micro 功能非常强大,本文将详细阐述micro api 命令行的功能 重要的事情说3次 本文全部代码https://idea.techidea8.com/open/idea.shtml?id=6 本文全部代码https://idea.techidea8....

非正式解决方案
今天
2
0
Spring Context 你真的懂了吗

今天介绍一下大家常见的一个单词 context 应该怎么去理解,正确的理解它有助于我们学习 spring 以及计算机系统中的其他知识。 1. context 是什么 我们经常在编程中见到 context 这个单词,当...

Java知其所以然
昨天
3
0
Spring Boot + Mybatis-Plus 集成与使用(二)

前言: 本章节介绍MyBatis-Puls的CRUD使用。在开始之前,先简单讲解下上章节关于Spring Boot是如何自动配置MyBatis-Plus。 一、自动配置 当Spring Boot应用从主方法main()启动后,首先加载S...

伴学编程
昨天
7
0
用最通俗的方法讲spring [一] ──── AOP

@[TOC](用最通俗的方法讲spring [一] ──── AOP) 写这个系列的目的(可以跳过不看) 自己写这个系列的目的,是因为自己是个比较笨的人,我曾一度怀疑自己的智商不适合干编程这个行业.因为在我...

小贼贼子
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部