高度模块化的设计是nginx的架构基础。在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将各功能组织成一条链,当有请求到达的时候,请求依次通过这条链上的部分或者所有模块进行处理。模块化
nginx模块分为核心模块和功能性模块,功能性模块包括conf、event、http、mail、stream几大类。除了conf类之外,其余几类功能性模块都包含众多的模块,而且每一个类别中都有一个核心模块。其主要做用是提供本类别功能通用的框架接口,逻辑处理等,并调用同类型的其余模块完成具体的功能。例如NGX_HTTP_MODULE类别中的核心模块ngx_http_core_module,负责http块配置项中通用的配置解析、http请求处理的总体流程,并调用其余NGX_HTTP_MODULE模块完成具体的处理。函数
nginx中经常使用模块分层分类:post
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 ;
执行configure后,会在objs目录下生成nginx_modules.c源文件。这个源文件中有两个很重要的全局变量ngx_modules和ngx_module_names,前者保存了nginx将要使用的所有模块,后者则记录了这些模块的名称。ui
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", ... };
初始化每一个模块的索引以及名称。spa
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开发从入门到精通》