摘要:結(jié)構(gòu)體數(shù)組,用來(lái)表示該模塊可以在配置文件中配置的項(xiàng)目,及其操作指令。
源文件路徑
srccore gx_conf_file.h srccore gx_conf_file.c主要內(nèi)容
本篇的主要目的在于分析Nginx的配置功能。由于Nginx的配置基本就是對(duì)模塊的配置,因此,在討論配置功能之前,需要先分析Nginx的模塊功能。
對(duì)于模塊功能,這里的重點(diǎn)不在于某個(gè)模塊的細(xì)節(jié),而在于分析Nginx的模塊架構(gòu)是如何設(shè)計(jì)的。
類似地,因?yàn)閷?duì)于Nginx的配置文件,沒(méi)有資料比官方文檔上說(shuō)得更明白,所以,這里的重點(diǎn)并不是對(duì)配置文件,而是分析Nginx的配置功能是如何設(shè)計(jì)的。
好了,開(kāi)始吧。
模塊功能Nginx的基礎(chǔ)架構(gòu)是高度模塊化的??梢詮亩鄠€(gè)方面來(lái)觀察Nginx的模塊化。
官方文檔首頁(yè)的整個(gè)下半頁(yè)是Nginx自身所有模塊的列表。從這里可以看到Nginx的模塊輪廓。
如果從源碼安裝Nginx,那么首先執(zhí)行的configure腳本的配置參數(shù)里,很大一部分是用來(lái)管理是否安裝某個(gè)模塊的。當(dāng)然,Nginx運(yùn)行必備的模塊是必須安裝的,因此,并不會(huì)出現(xiàn)在configure的配置選項(xiàng)里。
Nginx本身由多個(gè)基本的模塊構(gòu)成,其中,核心的部分是一個(gè)叫ngx_core_module的模塊。當(dāng)然,對(duì)于一個(gè)web服務(wù)器,僅僅有一個(gè)核心是不夠的,還需要大量的“輔助模塊”。這有點(diǎn)像Linux的設(shè)計(jì),一堆外圍設(shè)施作為模塊與Linux內(nèi)核構(gòu)成整個(gè)Linux系統(tǒng)。
很自然的會(huì)想到,Nginx的這種模塊化設(shè)計(jì)是支持第三方插件的。這種設(shè)計(jì)也大大增加了Nginx的彈性和能力。
模塊的組織和管理既然Nginx是由許多模塊構(gòu)成的,那么,如何組織和管理這些模塊是首先要關(guān)注的問(wèn)題。在Nginx中,使用全局?jǐn)?shù)組ngx_modules保存和管理所有Nginx的模塊。
如何做到的呢?
首先,Nginx的眾多模塊被分成兩類:必須安裝的模塊和可以安裝的模塊。
必須安裝的模塊是保證Nginx正常功能的模塊,沒(méi)得選擇,這些模塊會(huì)出現(xiàn)在ngx_modules里。比如ngx_core_module
可以安裝的模塊通過(guò)configure的配置和系統(tǒng)環(huán)境,被有選擇的安裝,這些模塊里,被選擇安裝的模塊會(huì)出現(xiàn)在ngx_modules數(shù)組中。
當(dāng)configure執(zhí)行結(jié)束后,會(huì)生成一個(gè)objs
gx_modules.c的源代碼文件:
文件內(nèi)容隨configure配置不同而不同,例如:
#include#include extern ngx_module_t ngx_core_module; extern ngx_module_t ngx_errlog_module; extern ngx_module_t ngx_conf_module; extern ngx_module_t ngx_events_module; extern ngx_module_t ngx_event_core_module; extern ngx_module_t ngx_epoll_module; extern ngx_module_t ngx_regex_module; extern ngx_module_t ngx_http_module; extern ngx_module_t ngx_http_core_module; extern ngx_module_t ngx_http_log_module; extern ngx_module_t ngx_http_upstream_module; extern ngx_module_t ngx_http_static_module; extern ngx_module_t ngx_http_autoindex_module; extern ngx_module_t ngx_http_index_module; ... ngx_module_t *ngx_modules[] = { &ngx_core_module, &ngx_errlog_module, &ngx_conf_module, &ngx_events_module, &ngx_event_core_module, &ngx_epoll_module, &ngx_regex_module, &ngx_http_module, &ngx_http_core_module, &ngx_http_log_module, &ngx_http_upstream_module, &ngx_http_static_module, &ngx_http_autoindex_module, &ngx_http_index_module, ... NULL };
由于數(shù)組存放的是同一類型的數(shù)據(jù)。因此,必須有一個(gè)模塊基類來(lái)抽象的定義所有模塊。這個(gè)抽象基類就是ngx_module_t。
因此,可以看到ngx_modules數(shù)組里存放的是ngx_module_t *類型指針,并且,最后一個(gè)一定是空指針NULL。
將最后一個(gè)元素置為空指針NULL,是為了遍歷數(shù)組的時(shí)候,標(biāo)記數(shù)組結(jié)束,這樣不必在使用時(shí)記錄數(shù)組大小。
例如:
for (i = 0; ngx_modules[i]; i++) { ... }
使用extern ngx_module_t ngx_core_module;使編譯器在編譯的時(shí)候不去處理ngx_core_module,在鏈接階段,再將ngx_core_module鏈接到正確的地址中。
類似地,在源文件core gx_conf_file.h的末尾聲明外部ngx_modules[]
extern ngx_module_t *ngx_modules[];
由于core gx_conf_file.h會(huì)被當(dāng)作公共頭文件被包含到其他文件中,因此,ngx_modules是一個(gè)全局變量。
======分割線=======
在編譯階段,objs
gx_modules.c文件中的那一堆extern變量及ngx_modules變量都會(huì)被初始化。原因在于,這些變量都屬于全局變量,將會(huì)被靜態(tài)初始化。
======分割線=======
這樣,有了全局?jǐn)?shù)組ngx_modules,就可以獲取所有模塊的指針,從而操作所有模塊。對(duì)所有模塊的管理和操作也由此展開(kāi)。
所有模塊的基類 ngx_module_t所有模塊都是ngx_module_t類型的變量,其定義如下:
struct ngx_module_s { ngx_uint_t ctx_index; ngx_uint_t index; ngx_uint_t spare0; ngx_uint_t spare1; ngx_uint_t spare2; ngx_uint_t spare3; ngx_uint_t version; 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_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; };
各成員變量含義如下:
1. type
type變量是指模塊的類型。Nginx中模塊的類型定義如下:
#define NGX_CORE_MODULE 0x45524F43 /* "CORE" */ #define NGX_CONF_MODULE 0x464E4F43 /* "CONF" */ #define NGX_EVENT_MODULE 0x544E5645 /* "EVNT" */ #define NGX_HTTP_MODULE 0x50545448 /* "HTTP" */ #define NGX_MAIL_MODULE 0x4C49414D /* "MAIL" */
也就是說(shuō),Nginx共有5中模塊類型CORF、CONF、EVNT、HTTP、MAIL。
2. index
index變量是指,該模塊在ngx_modules數(shù)組中的次序,或者說(shuō)下標(biāo)。該變量在Nginx執(zhí)行初始化的時(shí)候被初始化,初始化代碼位于core ginx.c的main函數(shù)中:
ngx_max_module = 0; for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]->index = ngx_max_module++; }
3. ctx_index
ctx_index是指,在ngx_modules數(shù)組中,該模塊在相同類型的模塊中的次序。
例如,ngx_modules數(shù)組中有多個(gè)類型為NGX_EVENT_MODULE的模塊,那么其中一個(gè)模塊的ctx_index初始化如下:
// 源碼文件event gx_event.c ngx_event_max_module = 0; for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_EVENT_MODULE) { continue; } ngx_modules[i]->ctx_index = ngx_event_max_module++; }
4. ctx
ctx是void *指針型變量,這是指向與模塊相關(guān)的上下文。
這里先解釋一下什么叫與模塊相關(guān)的上下文。
上下文這個(gè)概念一般可以理解為運(yùn)行環(huán)境,那么與模塊相關(guān)的上下文就是指模塊運(yùn)行環(huán)境。換句話說(shuō),就是一些參數(shù)的配置信息。因?yàn)榕渲靡话阋馕吨O(shè)置,而設(shè)置的對(duì)象就是模塊的運(yùn)行環(huán)境。比如,ngx_core_modules運(yùn)行時(shí)的user和group,就屬于運(yùn)行環(huán)境,同時(shí),也屬于配置項(xiàng)。
由于模塊的參數(shù)一般比較多,正確設(shè)置參數(shù)的配置需要很多操作。所以,上下文其實(shí)也意味著一組操作,這組操作的目的在于根據(jù)配置,正確設(shè)置模塊的參數(shù)信息。同時(shí),這也意味著,不同的模塊,這組操作是不同的,因此,這里需要將ctx設(shè)置為void *指針,來(lái)進(jìn)行泛型的操作。
以ngx_core_module為例,其ctx指向的上下文是這個(gè)樣子的:
static ngx_core_module_t ngx_core_module_ctx = { ngx_string("core"), ngx_core_module_create_conf, ngx_core_module_init_conf };
其中ngx_core_module_t的定義如下:
typedef struct { ngx_str_t name; void *(*create_conf)(ngx_cycle_t *cycle); char *(*init_conf)(ngx_cycle_t *cycle, void *conf); } ngx_core_module_t;
而這組操作中的ngx_core_module_init_conf函數(shù)中,初始化了一個(gè)ngx_core_conf_t的結(jié)構(gòu)體。
因此,可知,void *ctx指向了一組操作,這組操作的目的在于初始化一個(gè)與模塊配置信息相關(guān)的結(jié)構(gòu)體。
這里涉及到了三個(gè)結(jié)構(gòu)體:
ngx_module_t ngx_core_module:用來(lái)表示模塊本身,保存在ngx_modules數(shù)組中;
ngx_core_conf_t core_conf:用來(lái)保存對(duì)該模塊的配置信息;
ngx_core_module_t ngx_core_module_ctx:用來(lái)初始化ngx_core_conf_t中的成員變量;
6. commands
commands是ngx_command_t數(shù)組,表示一組配置文件中的可配項(xiàng)(指令)。
例如,在配置文件nginx.conf中worker_processes 1;對(duì)應(yīng)commands數(shù)組中的一項(xiàng),該項(xiàng)的定義如下,類型為ngx_command_t:
{ ngx_string("worker_processes"), NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, ngx_set_worker_processes, 0, 0, NULL }
其中ngx_command_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; void *post; };
所以,commands的含義在于該模塊的配置項(xiàng)在配置文件中的指令。
ngx_module_t 總結(jié)到這里,一個(gè)完整的模塊所需的各個(gè)部分逐漸顯露出來(lái)了:
ngx_module_t結(jié)構(gòu)體,用來(lái)表示模塊的定義,被放入ngx_modules數(shù)組中。
ngx_
ngx_
ngx_command_t結(jié)構(gòu)體數(shù)組,用來(lái)表示該模塊可以在配置文件中配置的項(xiàng)目,及其操作指令。在Nginx初始化解析配置文件后,調(diào)用ngx_command_t中的函數(shù)set初始化ngx_
在Nginx中,一個(gè)模塊運(yùn)行所需的各種配置參數(shù)被封裝成了ngx_
這個(gè)結(jié)構(gòu)體內(nèi)成員變量的初始化被分成了兩部分:
模塊相關(guān)的上下文ngx_
配置文件相關(guān)指令ngx_command_t:即規(guī)定了配置文件中可以使用的指令及其對(duì)應(yīng)的操作函數(shù)。
而模塊本身被封裝成了ngx_module_t類型結(jié)構(gòu)體,被用來(lái)供Nginx統(tǒng)一管理和使用。
模塊和配置的聯(lián)系非常緊密,因此,這里僅僅先大略的分析一下模塊功能的整體框架,下一篇中,將在本篇的基礎(chǔ)上分析Nginx的配置功能。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/39155.html
摘要:每個(gè)模塊由以下幾部分構(gòu)成結(jié)構(gòu)體代表模塊本身,其指針被放入數(shù)組中。結(jié)構(gòu)體用來(lái)表示模塊的配置內(nèi)容,其中部分成員可以通過(guò)配置文件進(jìn)行配置。調(diào)用該中的函數(shù),該函數(shù)最終初始化模塊對(duì)應(yīng)的結(jié)構(gòu)體,完成配置。因此,分析源碼中的配置指令,就是分析結(jié)構(gòu)體。 本篇的上篇 Nginx 源碼分析:從模塊到配置(上),建議閱讀本篇前先閱讀上篇。 關(guān)于模塊 Nginx的架構(gòu)高度模塊化。每個(gè)模塊各司其職,組合在一...
摘要:本文將從源碼從此深入分析配置文件的解析,配置存儲(chǔ),與配置查找。在學(xué)習(xí)配置文件的解析過(guò)程之前,需要先了解一下模塊與指令的一些基本知識(shí)。 運(yùn)營(yíng)研發(fā)團(tuán)隊(duì) 李樂(lè) 配置文件是nginx的基礎(chǔ),對(duì)于學(xué)習(xí)nginx源碼甚至開(kāi)發(fā)nginx模塊的同學(xué)來(lái)說(shuō)更是必須深究。本文將從源碼從此深入分析nginx配置文件的解析,配置存儲(chǔ),與配置查找。 看本文之前讀者可以先思考兩個(gè)問(wèn)題: 1.nginx源碼中隨處可以...
摘要:四監(jiān)聽(tīng)套接字的使用假設(shè)此處我們使用作為事件處理模塊在增加事件時(shí)用戶可以使用中的字段當(dāng)事件發(fā)生時(shí)該字段也會(huì)帶回。在創(chuàng)建監(jiān)聽(tīng)套接字時(shí)將結(jié)構(gòu)分為級(jí)監(jiān)聽(tīng)套接字地址各級(jí)都是一對(duì)多的關(guān)系。 施洪寶 一. 基礎(chǔ) nginx源碼采用1.15.5 后續(xù)部分僅討論http中的listen配置解析以及優(yōu)化流程 1.1 概述 假設(shè)nginx http模塊的配置如下 http{ server { ...
摘要:現(xiàn)在使用的各種哈希函數(shù)基本上只能保證較小概率出現(xiàn)兩個(gè)不同的其相同的情況。而出現(xiàn)兩個(gè)值對(duì)應(yīng)的相同的情況,稱為哈希沖突。中的哈希表需要指出的是,中自造的哈希表屬于內(nèi)部使用的數(shù)據(jù)結(jié)構(gòu),因此,并不是一個(gè)通用的哈希表。 源文件路徑 版本:1.8.0 csrccoreNgx_hash.h srccoreNgx_hash.c 關(guān)于hash表 Nginx實(shí)現(xiàn)的hash表和常見(jiàn)的hash表大體...
閱讀 3191·2019-08-30 15:55
閱讀 2953·2019-08-30 13:46
閱讀 1455·2019-08-29 17:29
閱讀 3524·2019-08-29 11:08
閱讀 3449·2019-08-29 11:04
閱讀 1096·2019-08-28 18:20
閱讀 553·2019-08-26 13:37
閱讀 1340·2019-08-26 11:49