nginx模块化分析

模块管理是nginx非常有魅力的功能。

ngx_modules数组包含了所有注册使用的模块,该数组定义在objs/ngx_modules.c中:

55 ngx_module_t *ngx_modules[] = {
56     &ngx_core_module,
57     &ngx_errlog_module,
58     &ngx_conf_module,
59     &ngx_events_module,

nginx通过给模块设置类型来支持多级模块:

顶级模块的类型是NGX_CORE_MODULE;

如果某个模块支持子模块,给其子模块指定一种模块类型(如NGX_EVENT_MODULE和NGX_HTTP_MODULE),可以通过它的某个block指令来加载其子模块(如events和http);

初始化时,先初始化CORE模块,再递归加载CORE模块的子模块;

上级模块开辟一个context数组保存下级模块的context,通过这种方式构成一个模块森林;

ngx_cycle_t::conf_ctx是void *数组,保存着NGX_CORE_MODULE的context;

ngx_events_module的context也是一个void *数组,保存着events二级模块的context;

ngx_http_module是ngx_http_conf_ctx_t的指针,ngx_http_conf_ctx_t包含三个类型数组(main、srv和loc),保存着http二级模块的context;

nginx默认支持的模块有:

ngx_core_module

ngx_events_module

ngx_event_core_module

ngx_epoll_module

......

ngx_http_module

ngx_http_core_module

ngx_http_fastcgi_module

......

......

ngx_conf_module比较特殊,该模块不受模块类型限制,任何地方都有效;

其仅有一个include命令,实现类似c的include预处理命令功能,这样使得配置文件可以分文件管理;

模块的结构体如下所示:

102 struct ngx_module_s {
103     ngx_uint_t            ctx_index;    /* 父模块的所有子模块组成一个数组,为子模块开辟context数组:ctx_index表示当前模块在其父模块这个数组中的下标 */
104     ngx_uint_t            index;        /* 模块在ngx_modules数组中的下标 */
105 
106     ngx_uint_t            spare0;
107     ngx_uint_t            spare1;
108     ngx_uint_t            spare2;
109     ngx_uint_t            spare3;
110 
111     ngx_uint_t            version;
112 
113     void                 *ctx;          /* 模块context;同一个级别的模块一般格式相同;譬如core模块、event子模块、http子模块等 */
114     ngx_command_t        *commands;     /* 模块支持的命令数组 */
115     ngx_uint_t            type;         /* 模块类型:NGX_CORE_MODULE, NGX_EVENT_MODULE, NGX_HTTP_MODULE等 */
116 
117     ngx_int_t           (*init_master)(ngx_log_t *log);         /* 在master进程启动时调用 */
118 
119     ngx_int_t           (*init_module)(ngx_cycle_t *cycle);     /* 在所有模块配置读取完毕后调用 */
120 
121     ngx_int_t           (*init_process)(ngx_cycle_t *cycle);    /* 在进程启动时调用 */
122     ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);     /* 在线程启动时调用 */
123     void                (*exit_thread)(ngx_cycle_t *cycle);     /* 在线程退出时调用 */
124     void                (*exit_process)(ngx_cycle_t *cycle);    /* 在进程退出时调用 */
125 
126     void                (*exit_master)(ngx_cycle_t *cycle);     /* 在master进程退出时调用 */
127 
128     uintptr_t             spare_hook0;
129     uintptr_t             spare_hook1;
130     uintptr_t             spare_hook2;
131     uintptr_t             spare_hook3;
132     uintptr_t             spare_hook4;
133     uintptr_t             spare_hook5;
134     uintptr_t             spare_hook6;
135     uintptr_t             spare_hook7;
136 };

core模块的context结构:

139 typedef struct {
140     ngx_str_t             name;    /* 模块名字 */
141     void               *(*create_conf)(ngx_cycle_t *cycle);              /* 创建模块config context */
142     char               *(*init_conf)(ngx_cycle_t *cycle, void *conf);    /* 读完配置后,初始化模块config context, conf即create_conf的返回值 */
143 } ngx_core_module_t;

event模块的context结构:

486 typedef struct {
487     ngx_str_t              *name;    /* name,create_conf,init_conf含义同core模块 */
488 
489     void                 *(*create_conf)(ngx_cycle_t *cycle);
490     char                 *(*init_conf)(ngx_cycle_t *cycle, void *conf);
491 
492     ngx_event_actions_t     actions;    /* event回调函数集 */
493 } ngx_event_module_t;

http模块的context结构:

24 typedef struct {
25     ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);     /* 在读http block下所有配置前调用 */
26     ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);    /* 在读完配置且init config后调用 */
27 
28     void       *(*create_main_conf)(ngx_conf_t *cf);              /* 创建main conf,全局一份 */
29     char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);    /* 读完http block下所有配置后调用 */
30 
31     void       *(*create_srv_conf)(ngx_conf_t *cf);                           /* 创建server conf,全局一份,每个server一份 */
32     char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);    /* 将全局属性merge到每个server,server继承自己没有配置但全局有配置的属性 */
33 
34     void       *(*create_loc_conf)(ngx_conf_t *cf);                           /* 创建location conf,全局一份,每个server一份,每个location一份 */
35     char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);    /* 将全局、server属性merge到location中 */
36 } ngx_http_module_t;

http模块的启动分析

http指令类型是NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,回调函数是ngx_http_block;

http指令类型传达三个含义:

第一,ngx_http_module的config context是由其回调函数ngx_http_block创建的(设置了NGX_MAIN_CONF但没有设置NGX_DIRECT_CONF);

第二,该指令是一个block;

第三,该指令无参数;

118 static char *
119 ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
120 {
121     char                        *rv;
122     ngx_uint_t                   mi, m, s;
123     ngx_conf_t                   pcf;
124     ngx_http_module_t           *module;
125     ngx_http_conf_ctx_t         *ctx;
126     ngx_http_core_loc_conf_t    *clcf;
127     ngx_http_core_srv_conf_t   **cscfp;
128     ngx_http_core_main_conf_t   *cmcf;
129 
130     /* the main http context */
131 
132     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));    /* 创建ngx_http_module的config context */
133     if (ctx == NULL) {
134         return NGX_CONF_ERROR;
135     }
136 
137     *(ngx_http_conf_ctx_t **) conf = ctx;    /* 保存config context到conf->ctx_conf数组 */
138 
139 
140     /* count the number of the http modules and set up their indices */
141 
142     ngx_http_max_module = 0;
143     for (m = 0; ngx_modules[m]; m++) {
144         if (ngx_modules[m]->type != NGX_HTTP_MODULE) {  /* NGX_HTTP_MODULE是http子模块的模块类型 */
145             continue;
146         }
147 
148         ngx_modules[m]->ctx_index = ngx_http_max_module++;
149     }
150 
151 
152     /* the http main_conf context, it is the same in the all http contexts */
153 
154     ctx->main_conf = ngx_pcalloc(cf->pool,
155                                  sizeof(void *) * ngx_http_max_module);
156     if (ctx->main_conf == NULL) {
157         return NGX_CONF_ERROR;
158     }
159 
160 
161     /*
162      * the http null srv_conf context, it is used to merge
163      * the server{}s' srv_conf's
164      */
165 
166     ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
167     if (ctx->srv_conf == NULL) {
168         return NGX_CONF_ERROR;
169     }
170 
171 
172     /*
173      * the http null loc_conf context, it is used to merge
174      * the server{}s' loc_conf's
175      */
176 
177     ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
178     if (ctx->loc_conf == NULL) {
179         return NGX_CONF_ERROR;
180     }
181 
182 
183     /*
184      * create the main_conf's, the null srv_conf's, and the null loc_conf's
185      * of the all http modules
186      */
187 
188     for (m = 0; ngx_modules[m]; m++) {
189         if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
190             continue;
191         }
192 
193         module = ngx_modules[m]->ctx;
194         mi = ngx_modules[m]->ctx_index;
195 
196         if (module->create_main_conf) {
197             ctx->main_conf[mi] = module->create_main_conf(cf);
198             if (ctx->main_conf[mi] == NULL) {
199                 return NGX_CONF_ERROR;
200             }
201         }
202 
203         if (module->create_srv_conf) {
204             ctx->srv_conf[mi] = module->create_srv_conf(cf);
205             if (ctx->srv_conf[mi] == NULL) {
206                 return NGX_CONF_ERROR;
207             }
208         }
209 
210         if (module->create_loc_conf) {
211             ctx->loc_conf[mi] = module->create_loc_conf(cf);
212             if (ctx->loc_conf[mi] == NULL) {
213                 return NGX_CONF_ERROR;
214             }
215         }
216     }
217 
218     pcf = *cf;        /* 保存上级block的context现场,以便在http block解析完毕后,恢复上级block的现场 */
219     cf->ctx = ctx;    /* 更新context数组,为加载http子模块命令做准备 */
220 
221     for (m = 0; ngx_modules[m]; m++) {
222         if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
223             continue;
224         }
225 
226         module = ngx_modules[m]->ctx;
227 
228         if (module->preconfiguration) {
229             if (module->preconfiguration(cf) != NGX_OK) {    /* 加载配置前,为http子模块调用preconfiguration回调 */
230                 return NGX_CONF_ERROR;
231             }
232         }
233     }
234 
235     /* parse inside the http{} block */
236 
237     cf->module_type = NGX_HTTP_MODULE;    /* 此处设置模块类型为NGX_HTTP_MODULE */
238     cf->cmd_type = NGX_HTTP_MAIN_CONF;    /* 此处设置命令类型为NGX_HTTP_MAIN_CONF,和上一句结合起来,即仅加载http子模块中NGX_HTTP_MAIN_CONF类型的命令 */
239     rv = ngx_conf_parse(cf, NULL);        /* parse http block */
240 
241     if (rv != NGX_CONF_OK) {
242         goto failed;
243     }
244 
245     /*
246      * init http{} main_conf's, merge the server{}s' srv_conf's
247      * and its location{}s' loc_conf's
248      */
249 
250     cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
251     cscfp = cmcf->servers.elts;
252 
253     for (m = 0; ngx_modules[m]; m++) {
254         if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
255             continue;
256         }
257 
258         module = ngx_modules[m]->ctx;
259         mi = ngx_modules[m]->ctx_index;
260 
261         /* init http{} main_conf's */
262 
263         if (module->init_main_conf) {
264             rv = module->init_main_conf(cf, ctx->main_conf[mi]);
265             if (rv != NGX_CONF_OK) {
266                 goto failed;
267             }
268         }
269 
270         rv = ngx_http_merge_servers(cf, cmcf, module, mi);    /* merge server和location配置,实现server、location配置继承功能 */
271         if (rv != NGX_CONF_OK) {
272             goto failed;
273         }
274     }
275 
276 
277     /* create location trees */
278 
279     for (s = 0; s < cmcf->servers.nelts; s++) {
280 
281         clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
282 
283         if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {    /* 将locations排序、分类:1、exact_match、noregex和普通location按字母序存放在ngx_http_core_loc_conf_t::locations队列中(当路径相同时,excact_match排在前面);2、regex location按定义顺序存放在ngx_http_core_loc_conf_t::regex_locations数组中;3、named location按字母序存放在ngx_http_core_srv_conf_t::named_locations中;4、noname locations被丢弃; */
284             return NGX_CONF_ERROR;
285         }
286 
287         if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {    /* 将ngx_http_core_loc_conf_t::locations中保存的路径转变成一个高效的前缀匹配字典 */
288             return NGX_CONF_ERROR;
289         }
290     }
291 
292 
293     if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {    /* 初始化phases */
294         return NGX_CONF_ERROR;
295     }
296 
297     if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) {    /* 为http headers构建hash表 */
298         return NGX_CONF_ERROR;
299     }
300 
301 
302     for (m = 0; ngx_modules[m]; m++) {
303         if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
304             continue;
305         }
306 
307         module = ngx_modules[m]->ctx;
308 
309         if (module->postconfiguration) {
310             if (module->postconfiguration(cf) != NGX_OK) {    /* 配置加载完毕后,为http子模块调用postconfiguration回调,注册phase handlers */
311                 return NGX_CONF_ERROR;
312             }
313         }
314     }
315 
316     if (ngx_http_variables_init_vars(cf) != NGX_OK) {
317         return NGX_CONF_ERROR;
318     }
319 
320     /*
321      * http{}'s cf->ctx was needed while the configuration merging
322      * and in postconfiguration process
323      */
324 
325     *cf = pcf;    /* 恢复上级block的parse现场 */
326 
327 
328     if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {    /* 根据注册的phase handlers初始化phase_engine */
329         return NGX_CONF_ERROR;
330     }
331 
332 
333     /* optimize the lists of ports, addresses and server names */
334 
335     if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
336         return NGX_CONF_ERROR;
337     }
338 
339     return NGX_CONF_OK;
340 
341 failed:
342 
343     *cf = pcf;
344 
345     return rv;
346 }
在parse server和location block时,因为它们有自己的context,所以也需要保存和恢复上级parse现场;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值