Content
0. 序
1. nginx有哪些模块?
2. nginx如何描述这些模块?
2.1 模块数据结构
2.1.1 ngx_module_t结构
2.1.2 ngx_command_t结构
2.2 模块类图
3. nginx如何组织这些模块?
3.1 全局数组ngx_modules
3.2 模块组织结构图
4. nginx的模块种类
5. nginx如何初始化这些模块?
5.1 静态初始化
5.2 动态初始化
5.2.1 index字段的初始化
5.2.2 ctx_index字段的初始化
5.2.3 其他初始化
6. 小结
0. 序
本文以nginx-1.0.4版本为例,介绍nginx的模块及其初始化。.表示nginx-1.0.4源代码目录,本文为/usr/src/nginx-1.0.4。
1. nginx有哪些模块?
要知道nginx有哪些模块,一个快速的方法就是编译nginx。编译之后,会在源代码根目录下生成objs目录,该目录中包含有ngx_auto_config.h和ngx_auto_headers.h,以及ngx_modules.c文件,当然,还有Makefile文件等。
其中,生成的ngx_modules.c文件中,重新集中申明(使用extern关键字)了nginx配置的所有模块,这些模块可通过编译前的configure命令进行配置,即设置哪些模块需要编译,哪些不被编译。如下。
- 00001:
- 00002: #include <ngx_config.h>
- 00003: #include <ngx_core.h>
- 00004:
- 00005:
- 00006:
- 00007: extern ngx_module_t ngx_core_module;
- 00008: extern ngx_module_t ngx_errlog_module;
- 00009: extern ngx_module_t ngx_conf_module;
- 00010: extern ngx_module_t ngx_events_module;
- 00011: extern ngx_module_t ngx_event_core_module;
- 00012: extern ngx_module_t ngx_epoll_module;
- 00013: extern ngx_module_t ngx_http_module;
- 00014: extern ngx_module_t ngx_http_core_module;
- 00015: extern ngx_module_t ngx_http_log_module;
- 00016: extern ngx_module_t ngx_http_upstream_module;
- 00017: extern ngx_module_t ngx_http_static_module;
- 00018: extern ngx_module_t ngx_http_autoindex_module;
- 00019: extern ngx_module_t ngx_http_index_module;
- 00020: extern ngx_module_t ngx_http_auth_basic_module;
- 00021: extern ngx_module_t ngx_http_access_module;
- 00022: extern ngx_module_t ngx_http_limit_zone_module;
- 00023: extern ngx_module_t ngx_http_limit_req_module;
- 00024: extern ngx_module_t ngx_http_geo_module;
- 00025: extern ngx_module_t ngx_http_map_module;
- 00026: extern ngx_module_t ngx_http_split_clients_module;
- 00027: extern ngx_module_t ngx_http_referer_module;
- 00028: extern ngx_module_t ngx_http_rewrite_module;
- 00029: extern ngx_module_t ngx_http_proxy_module;
- 00030: extern ngx_module_t ngx_http_fastcgi_module;
- 00031: extern ngx_module_t ngx_http_uwsgi_module;
- 00032: extern ngx_module_t ngx_http_scgi_module;
- 00033: extern ngx_module_t ngx_http_memcached_module;
- 00034: extern ngx_module_t ngx_http_empty_gif_module;
- 00035: extern ngx_module_t ngx_http_browser_module;
- 00036: extern ngx_module_t ngx_http_upstream_ip_hash_module;
- 00037: extern ngx_module_t ngx_http_stub_status_module;
- 00038: extern ngx_module_t ngx_http_write_filter_module;
- 00039: extern ngx_module_t ngx_http_header_filter_module;
- 00040: extern ngx_module_t ngx_http_chunked_filter_module;
- 00041: extern ngx_module_t ngx_http_range_header_filter_module;
- 00042: extern ngx_module_t ngx_http_gzip_filter_module;
- 00043: extern ngx_module_t ngx_http_postpone_filter_module;
- 00044: extern ngx_module_t ngx_http_ssi_filter_module;
- 00045: extern ngx_module_t ngx_http_charset_filter_module;
- 00046: extern ngx_module_t ngx_http_userid_filter_module;
- 00047: extern ngx_module_t ngx_http_headers_filter_module;
- 00048: extern ngx_module_t ngx_http_copy_filter_module;
- 00049: extern ngx_module_t ngx_http_range_body_filter_module;
- 00050: extern ngx_module_t ngx_http_not_modified_filter_module;
- 00051:
很显然,这些模块均是在此处用extern进行申明,以表明其他模块可以访问,而对其本身的定义和初始化ngx_module_t结构在其对应的.c文件中进行。例如,ngx_core_module模块便是在./src/core/nginx.c文件中定义并进行静态初始化。实际上,ngx_core_module是一个全局的结构体对象,其他模块类同。如下。
- ngx_module_t ngx_core_module = {
- NGX_MODULE_V1,
- &ngx_core_module_ctx, /* module context */
- ngx_core_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
- };
2. nginx如何描述这些模块?
2.1 模块数据结构
2.1.1 ngx_module_t结构
nginx的模块化架构最基本的数据结构为ngx_module_t,因此,此处,我们先分析这个结构,在./src/core/ngx_conf_file.h文件中定义。如下,//后的内容为笔者加入的注释。
- 00107: #define NGX_MODULE_V1 0, 0, 0, 0, 0, 0, 1 //该宏用来初始化前7个字段
- 00108: #define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0 //该宏用来初始化最后8个字段
- 00109:
- 00110: struct ngx_module_s{
- 00111: ngx_uint_t ctx_index; //分类模块计数器
- 00112: ngx_uint_t index; //模块计数器
- 00113:
- 00114: ngx_uint_t spare0;
- 00115: ngx_uint_t spare1;
- 00116: ngx_uint_t spare2;
- 00117: ngx_uint_t spare3;
- 00118:
- 00119: ngx_uint_t version; //版本
- 00120:
- 00121: void *ctx; //该模块的上下文,每个种类的模块有不同的上下文
- 00122: ngx_command_t *commands; //该模块的命令集,指向一个ngx_command_t结构数组
- 00123: ngx_uint_t type; //该模块的种类,为core/event/http/mail中的一种
- 00124: //以下是一些callback函数
- 00125: ngx_uint_t (*init_master)(ngx_log_t *log); //初始化master
- 00126:
- 00127: ngx_uint_t (*init_module)(ngx_cycle_t *cycle); //初始化模块
- 00128:
- 00129: ngx_uint_t (*init_process)(ngx_cycle_t *cycle); //初始化工作进程
- 00130: ngx_uint_t (*init_thread)(ngx_cycle_t *cycle); //初始化线程
- 00131: void (*exit_thread)(ngx_cycle_t *cycle); //退出线程
- 00132: void (*exit_process)(ngx_cycle_t *cycle); //退出工作进程
- 00133:
- 00134: void (*exit_master)(ngx_cycle_t *cycle); //退出master
- 00135:
- 00136: uintptr_t spare_hook0; //这些字段貌似没用过
- 00137: uintptr_t spare_hook1;
- 00138: uintptr_t spare_hook2;
- 00139: uintptr_t spare_hook3;
- 00140: uintptr_t spare_hook4;
- 00141: uintptr_t spare_hook5;
- 00142: uintptr_t spare_hook6;
- 00143: uintptr_t spare_hook7;
- 00144: };
其中,init_master, init_module, init_process, init_thread, exit_thread, exit_process, exit_master分别在初始化master、初始化模块、初始化工作进程、初始化线程、退出线程、退出工作进程、退出master时被调用。
2.1.2 ngx_command_t结构
模块的命令集commands指向一个ngx_command_t结构数组,在./src/core/ngx_conf_file.h文件中定义。如下,//后的内容为笔者加入的注释。
- 00077: struct ngx_command_s {
- 00078: ngx_str_t name; //命令名
- 00079: ngx_uint_t type; //命令类型
- 00080: char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
- 00081: ngx_uint_t conf;
- 00082: ngx_uint_t offset;
- 00083: void *post;
- 00084: };
- 00085:
- 00086: #define ngx_null_command { ngx_null_string, 0, NULL, 0, 0, NULL } //空命令
2.2 模块类图
nginx为C语言开发的开源高性能web server,其代码中大量使用了callback方式,例如模块结构ngx_module_t中的init_master等。实际上,我们可以将ngx_module_t看作C++的一个类,其中的数据字段便是其属性,而那些callback便是该类的操作。
——这应该就是nginx的模块化思想。画出的ngx_module_t的类图如下。
3. nginx如何组织这些模块?
3.1 全局数组ngx_modules
由第1节,我们知道,nginx拥有几十个模块,那么,这些模块是如何组织的呢?
——保存在一个全局指针数组ngx_modules[]中,数组的每一个元素均为一个全局ngx_module_t对象的指针。如下。请参考./objs/ngx_modules.c文件中的定义。
- 00052: ngx_module_t *ngx_modules[] = {
- 00053: &ngx_core_module,
- 00054: &ngx_errlog_module,
- 00055: &ngx_conf_module,
- 00056: &ngx_events_module,
- 00057: &ngx_event_core_module,
- 00058: &ngx_epoll_module,
- 00059: &ngx_http_module,
- 00060: &ngx_http_core_module,
- 00061: &ngx_http_log_module,
- 00062: &ngx_http_upstream_module,
- 00063: &ngx_http_static_module,
- 00064: &ngx_http_autoindex_module,
- 00065: &ngx_http_index_module,
- 00066: &ngx_http_auth_basic_module,
- 00067: &ngx_http_access_module,
- 00068: &ngx_http_limit_zone_module,
- 00069: &ngx_http_limit_req_module,
- 00070: &ngx_http_geo_module,
- 00071: &ngx_http_map_module,
- 00072: &ngx_http_split_clients_module,
- 00073: &ngx_http_referer_module,
- 00074: &ngx_http_rewrite_module,
- 00075: &ngx_http_proxy_module,
- 00076: &ngx_http_fastcgi_module,
- 00077: &ngx_http_uwsgi_module,
- 00078: &ngx_http_scgi_module,
- 00079: &ngx_http_memcached_module,
- 00080: &ngx_http_empty_gif_module,
- 00081: &ngx_http_browser_module,
- 00082: &ngx_http_upstream_ip_hash_module,
- 00083: &ngx_http_stub_status_module,
- 00084: &ngx_http_write_filter_module,
- 00085: &ngx_http_header_filter_module,
- 00086: &ngx_http_chunked_filter_module,
- 00087: &ngx_http_range_header_filter_module,
- 00088: &ngx_http_gzip_filter_module,
- 00089: &ngx_http_postpone_filter_module,
- 00090: &ngx_http_ssi_filter_module,
- 00091: &ngx_http_charset_filter_module,
- 00092: &ngx_http_userid_filter_module,
- 00093: &ngx_http_headers_filter_module,
- 00094: &ngx_http_copy_filter_module,
- 00095: &ngx_http_range_body_filter_module,
- 00096: &ngx_http_not_modified_filter_module,
- 00097: NULL
- 00098: };
- 00099:
3.2 模块组织结构图
共44个模块,这些模块的组织结构图如下所示,因模块较多,图中只画出一部分有代表性的重要模块。
4. nginx的模块种类
在对全局数组ngx_modules进行初始化时,即对每一个模块进行了静态初始化。其中对模块的type字段的初始化是通过以下4个宏进行的。
(1) 文件./src/core/ngx_conf_file.h
- #define NGX_CORE_MODULE 0x45524F43 /* "CORE" */
- #define NGX_CONF_MODULE 0x464E4F43 /* "CONF" */
(2) 文件./src/event/ngx_event.h
- #define NGX_EVENT_MODULE 0x544E5645 /* "EVNT" */
- #define NGX_EVENT_MODULE 0x544E5645 /* "EVNT" */
(3) 文件./src/http/ngx_http_config.h
- #define NGX_HTTP_MODULE 0x50545448 /* "HTTP" */
即模块种类宏,定义为一个十六进制的数,这个十六进制的数就是其类型对应的ASCII码。因此,nginx共有4种类型的模块,分别为"CORE","CONF","EVNT","HTTP"。
实际上,如果在configure阶段,使用了"--with-mail"参数,mail模块将被编译进来,其对应的宏如下。
- #define NGX_MAIL_MODULE 0x4C49414D /* "MAIL" */
因此,严格来讲,nginx有5中类型的模块,"CORE","CONF","EVNT","HTTP","MAIL"。
5. nginx如何初始化这些模块?
5.1 静态初始化
即编译期间完成的数据成员初始化。记mname为某个模块的名字,其静态初始化过程如下。
(1) 用宏NGX_MODULE_V1初始化前7个字段
(2) 用全局对象ngx_mname_module_ctx的地址初始化ctx指针
(3) 用全局数组ngx_mname_commands[]初始化commands指针
(4) 用宏NGX_CORE_MODULE等初始化type字段
(5) 初始化init_master等callback
(6) 用宏NGX_MODULE_V1_PADDING初始化最后8个字段
由此可见,在定义该模块(全局结构对象)时,将其ctx_index和index均初始化为0。因此,模块的静态初始化(数据成员初始化)实际上只是对模块上下文、模块命令集和模块类型进行初始化。
5.2 动态初始化
即nginx运行(启动)初期,对模块本身的初始化。
5.2.1 index字段的初始化
对各个模块的index字段的初始化是在main函数中进行的,如下。
- 00325: ngx_max_module = 0;
- 00326: for (i = 0; ngx_modules[i]; i++) {
- 00327: ngx_modules[i]->index = ngx_max_module++;
- 00328: }
可见,该for-loop执行后,每个模块的index值便是其在ngx_modules[]数组中的下标值,且全局变量ngx_max_module为模块个数,对于本例来讲,ngx_max_module=44。
5.2.2 ctx_index字段的初始化
(1) "EVNT"类型的模块
- 00877: static char *
- 00878: ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
- 00879: {
- 00880: char *rv;
- 00881: void ***ctx;
- 00882: ngx_uint_t i;
- 00883: ngx_conf_t pcf;
- 00884: ngx_event_module_t *m;
- 00885:
- 00886: /* count the number of the event modules and set up their indices */
- 00887:
- 00888: ngx_event_max_module = 0;
- 00889: for (i = 0; ngx_modules[i]; i++) {
- 00890: if (ngx_modules[i]->type ! = NGX_EVENT_MODULE) {
- 00891: continue;
- 00892: }
- 00893:
- 00894: ngx_modules[i]->ctx_index = ngx_event_max_module++;
- 00895: }
- 00896:
- ...
(2) "HTTP"类型的模块
- 00117: static char *
- 00118: ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
- 00119: {
- 00120: char *rv;
- 00121: ngx_uint_t mi, m, s;
- 00122: ngx_conf_t pcf;
- 00123: ngx_http_module_t *module;
- 00124: ngx_http_conf_ctx_t *ctx;
- 00125: ngx_http_core_loc_conf_t *clcf;
- 00126: ngx_http_core_srv_conf_t **cscfp;
- 00127: ngx_http_core_main_conf_t *cmcf;
- 00128:
- 00129: /* the main http context */
- 00130:
- 00131: ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
- 00132: if (ctx == NULL) {
- 00133: return NGX_CONF_ERROR;
- 00134: }
- 00135:
- 00136: *(ngx_http_conf_ctx_t **) conf = ctx;
- 00137:
- 00138:
- 00139: /* count the number of the http modules and set up their indices */
- 00140:
- 00141: ngx_http_max_module = 0;
- 00142: for (m = 0; ngx_modules[m]; m++) {
- 00143: if (ngx_modules[m]->type ! = NGX_HTTP_MODULE) {
- 00144: continue;
- 00145: }
- 00146:
- 00147: ngx_modules[m]->ctx_index = ngx_http_max_module++;
- 00148: }
- 00149:
- ...
(3) "MAIL"类型的模块
- 00072: static char *
- 00073: ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
- 00074: {
- 00075: char *rv;
- 00076: ngx_uint_t i, m, mi, s;
- 00077: ngx_conf_t pcf;
- 00078: ngx_array_t ports;
- 00079: ngx_mail_listen_t *listen;
- 00080: ngx_mail_module_t *module;
- 00081: ngx_mail_conf_ctx_t *ctx;
- 00082: ngx_mail_core_srv_conf_t **cscfp;
- 00083: ngx_mail_core_main_conf_t *cmcf;
- 00084:
- 00085: if (cmd->name.data[0] == 'i') {
- 00086: ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- 00087: "the \"imap\" directive is deprecated, "
- 00088: "use the \"mail\" directive instead");
- 00089: }
- 00090:
- 00091: /* the main mail context */
- 00092:
- 00093: ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
- 00094: if (ctx == NULL) {
- 00095: return NGX_CONF_ERROR;
- 00096: }
- 00097:
- 00098: *(ngx_mail_conf_ctx_t **) conf = ctx;
- 00099:
- 00100: /* count the number of the http modules and set up their indices */
- 00101:
- 00102: ngx_mail_max_module = 0;
- 00103: for (m = 0; ngx_modules[m]; m++) {
- 00104: if (ngx_modules[m]->type ! = NGX_MAIL_MODULE) {
- 00105: continue;
- 00106: }
- 00107:
- 00108: ngx_modules[m]->ctx_index = ngx_mail_max_module++;
- 00109: }
- 00110:
- ...
5.2.3 其他初始化
其他的初始化工作,将在nginx启动及其进程启动分析中介绍。
6. 小结
本文主要讲述了nginx的模块及其初始化,包括所有模块的组织,及模块的静态初始化和部分动态初始化。