關(guān)于nginx事件模塊結(jié)構(gòu)體的詳解

事件模塊nginx的核心模塊之一,nginx中客戶端請求的處理和命令行指令的執(zhí)行都是基于事件模塊進(jìn)行驅(qū)動的。因此,掌握事件模塊的實現(xiàn)原理對于我們理解nginx整體架構(gòu)有非常重要的意義。

關(guān)于nginx事件模塊結(jié)構(gòu)體的詳解

本文首先會講解事件模塊相關(guān)的幾個模塊定義及其執(zhí)行流程進(jìn)行講解,其源碼的講解將會在后面的文章中進(jìn)行。

推薦教程:Nginx教程

nginx的事件核心模塊主要有兩個:ngx_events_module和ngx_event_core_module。這兩個模塊的主要區(qū)別在于,ngx_events_module的類型為NGX_CORE_MODULE,其本質(zhì)上雖然是核心模塊類型,但是卻是事件模塊的一個驅(qū)動點,其解析的配置項為events {},并且會創(chuàng)建用于存儲事件模塊相關(guān)配置的結(jié)構(gòu)體;

而ngx_event_core_module的類型則是NGX_EVENT_MODULE,這個模塊的配置對象中會存儲事件模塊的基礎(chǔ)配置對象,其主要作用是解析events{}配置塊中的子配置項。

下面我們就來看一下這兩個模塊的基礎(chǔ)配置。

1. ngx_events_module

?如下是ngx_events_module模塊的基礎(chǔ)配置:

ngx_module_t?ngx_events_module?=?{ ????NGX_MODULE_V1, ????&ngx_events_module_ctx,????????????????/*?module?context?*/ ????ngx_events_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 }; static?ngx_core_module_t?ngx_events_module_ctx?=?{ ????ngx_string("events"), ????NULL, ????ngx_event_init_conf }; static?ngx_command_t?ngx_events_commands[]?=?{ ????{ngx_string("events"), ?????NGX_MAIN_CONF?|?NGX_CONF_BLOCK?|?NGX_CONF_NOARGS, ?????ngx_events_block, ?????0, ?????0, ?????NULL}, ????ngx_null_command };

在ngx_events_module模塊的定義中,其module context指向的是ngx_events_module_ctx,也即第二個結(jié)構(gòu)體的配置,而module directives指向的則是ngx_events_commands,也即第三個結(jié)構(gòu)體的定義。可以看到,ngx_events_commands中只定義了一個events配置項,而這個配置項的類型為NGX_CONF_BLOCK,也就是說其是一個配置塊的類型,這里我們就理解了,這個command對應(yīng)的就是我們在nginx.conf中使用的events {}配置塊,而這個配置塊的解析則是通過ngx_events_block()方法進(jìn)行的。

我們知道,在nginx的核心配置對象ngx_cycle_t中的conf_ctx數(shù)組中,每個模塊在數(shù)組對應(yīng)的位置都會有一個配置對象,同理,這里的核心模塊也會有一個配置對象,但是上面的第二個結(jié)構(gòu)體ngx_events_module_ctx中的第二個屬性值為NULL,也就是說這里的事件模塊的定義中是沒有創(chuàng)建配置對象的方法的,但是卻有初始化配置對象的方法,也即第三個屬性值ngx_event_init_conf()方法。

那么這里事件模塊的配置對象是在哪里創(chuàng)建的呢?

其實其就是在解析配置對象的時候進(jìn)行的,也即在執(zhí)行解析events {}配置塊的ngx_events_block()方法中進(jìn)行的。該方法本質(zhì)上只是創(chuàng)建了一個指針數(shù)組,然后將其賦值給nginx核心和值對象的ngx_cycle_t的conf_ctx的對應(yīng)位置。

2. ngx_event_core_module

在介紹ngx_event_core_module模塊之前,我們首先需要講解一下事件模塊的接口定義:

typedef?struct?{ ????//?事件模塊的名稱 ????ngx_str_t?*name; ????//?在解析配置項前,這個回調(diào)方法用于創(chuàng)建存儲配置項參數(shù)的結(jié)構(gòu)體 ????void?*(*create_conf)(ngx_cycle_t?*cycle); ????//?在解析配置項完成后,init_conf()方法會被調(diào)用,用以綜合處理當(dāng)前事件模塊感興趣的全部配置項 ????char?*(*init_conf)(ngx_cycle_t?*cycle,?void?*conf); ????//?對于事件驅(qū)動機(jī)制,每個事件模塊需要實現(xiàn)的10個抽象方法 ????ngx_event_actions_t?actions; }?ngx_event_module_t; typedef?struct?{ ????//?添加事件方法,它負(fù)責(zé)把一個感興趣的事件添加到操作系統(tǒng)提供的事件驅(qū)動機(jī)制(epoll、kqueue等)中, ????//?這樣,在事件發(fā)生后,將可以在調(diào)用下面的process_events時獲取這個事件 ????ngx_int_t?(*add)(ngx_event_t?*ev,?ngx_int_t?event,?ngx_uint_t?flags); ????//?刪除事件方法,它把一個已經(jīng)存在于事件驅(qū)動機(jī)制中的事件移除,這樣以后即使這個事件發(fā)生, ????//?調(diào)用process_events()方法時也無法再獲取這個事件 ????ngx_int_t?(*del)(ngx_event_t?*ev,?ngx_int_t?event,?ngx_uint_t?flags); ????//?啟用一個事件,目前事件框架不會調(diào)用這個方法,大部分事件驅(qū)動模塊對于該方法的實現(xiàn)都是 ????//?與上面的add()方法完全一致的 ????ngx_int_t?(*enable)(ngx_event_t?*ev,?ngx_int_t?event,?ngx_uint_t?flags); ????//?禁用一個事件,目前事件框架不會調(diào)用這個方法,大部分事件驅(qū)動模塊對于該方法的實現(xiàn)都是 ????//?與上面的del()方法完全一致的 ????ngx_int_t?(*disable)(ngx_event_t?*ev,?ngx_int_t?event,?ngx_uint_t?flags); ????//?向事件驅(qū)動機(jī)制中添加一個新的連接,這意味著連接上的讀寫事件都添加到事件驅(qū)動機(jī)制中了 ????ngx_int_t?(*add_conn)(ngx_connection_t?*c); ????//?從事件驅(qū)動機(jī)制中移除一個連接的讀寫事件 ????ngx_int_t?(*del_conn)(ngx_connection_t?*c,?ngx_uint_t?flags); ????ngx_int_t?(*notify)(ngx_event_handler_pt?handler); ????//?在正常的工作循環(huán)中,將通過調(diào)用process_events()方法來處理事件。 ????//?這個方法僅在ngx_process_events_and_timers()方法中調(diào)用,它是處理、分發(fā)事件的核心 ????ngx_int_t?(*process_events)(ngx_cycle_t?*cycle,?ngx_msec_t?timer,?ngx_uint_t?flags); ????//?初始化事件驅(qū)動模塊的方法 ????ngx_int_t?(*init)(ngx_cycle_t?*cycle,?ngx_msec_t?timer); ????//?退出事件驅(qū)動模塊前調(diào)用的方法 ????void?(*done)(ngx_cycle_t?*cycle); }?ngx_event_actions_t;

?nginx的事件模塊主要有兩個配置結(jié)構(gòu)體:ngx_event_module_t和ngx_event_actions_t兩個。從上面的定義中可以看出,ngx_event_module_t結(jié)構(gòu)體是引用了ngx_event_actions_t的。

ngx_event_module_t的作用主要是創(chuàng)建和初始化當(dāng)前模塊所需要的配置結(jié)構(gòu)體,而ngx_event_actions_t則主要定義了當(dāng)前事件模塊處理各個事件的方式,這個接口典型的實現(xiàn)接口是nginx定義的各個事件模型,比如epoll的ngx_epoll_module_ctx.actions和kqueue的ngx_kqueue_module_ctx.actions。從這里就可以看出,事件模塊的定義抽象了各個處理事件的模型的相關(guān)處理方法。

對于事件模塊而言,其有一個模塊是用于存儲事件相關(guān)的基礎(chǔ)配置的,即ngx_event_core_module,雖然實現(xiàn)了ngx_event_module_t接口,但是其不進(jìn)行具體的事件處理。如下是ngx_event_core_module模塊的定義:

ngx_module_t?ngx_event_core_module?=?{ ????NGX_MODULE_V1, ????&ngx_event_core_module_ctx,????????????/*?module?context?*/ ????ngx_event_core_commands,???????????????/*?module?directives?*/ ????NGX_EVENT_MODULE,??????????????????????/*?module?type?*/ ????NULL,??????????????????????????????????/*?init?master?*/ ????//?該方法主要是在master進(jìn)程啟動的過程中調(diào)用的,用于初始化時間模塊 ????ngx_event_module_init,?????????????????/*?init?module?*/ ????//?該方法是在各個worker進(jìn)程啟動之后調(diào)用的 ????ngx_event_process_init,????????????????/*?init?process?*/ ????NULL,??????????????????????????????????/*?init?thread?*/ ????NULL,??????????????????????????????????/*?exit?thread?*/ ????NULL,??????????????????????????????????/*?exit?process?*/ ????NULL,??????????????????????????????????/*?exit?master?*/ ????NGX_MODULE_V1_PADDING }; static?ngx_event_module_t?ngx_event_core_module_ctx?=?{ ????&event_core_name, ????ngx_event_core_create_conf,????????????/*?create?configuration?*/ ????ngx_event_core_init_conf,??????????????/*?init?configuration?*/ ????//?ngx_event_core_module_ctx并不直接負(fù)責(zé)TCP網(wǎng)絡(luò)事件的驅(qū)動, ????//?因而這里的ngx_event_actions_t中的方法都為NULL ????{NULL,?NULL,?NULL,?NULL,?NULL,?NULL,?NULL,?NULL,?NULL,?NULL} }; static?ngx_command_t?ngx_event_core_commands[]?=?{ ????//?連接池的大小,也即每個worker進(jìn)程中支持的TCP最大連接數(shù),它與connections配置項的意義是重復(fù)的 ????{ngx_string("worker_connections"), ?????NGX_EVENT_CONF?|?NGX_CONF_TAKE1, ?????ngx_event_connections, ?????0, ?????0, ?????NULL}, ?????//?確定選擇哪一個事件模塊作為事件驅(qū)動機(jī)制 ????{ngx_string("use"), ?????NGX_EVENT_CONF?|?NGX_CONF_TAKE1, ?????ngx_event_use, ?????0, ?????0, ?????NULL}, ?????//?對應(yīng)于ngx_event_s中的available屬性,對于epoll事件驅(qū)動模式來說,意味著在接收到一個新連接事件時, ?????//?調(diào)用accept以盡可能多地接收連接 ????{ngx_string("multi_accept"), ?????NGX_EVENT_CONF?|?NGX_CONF_FLAG, ?????ngx_conf_set_flag_slot, ?????0, ?????offsetof(ngx_event_conf_t,?multi_accept), ?????NULL}, ?????//?確定是否使用accept_mutex負(fù)載均衡鎖,默認(rèn)為開啟 ????{ngx_string("accept_mutex"), ?????NGX_EVENT_CONF?|?NGX_CONF_FLAG, ?????ngx_conf_set_flag_slot, ?????0, ?????offsetof(ngx_event_conf_t,?accept_mutex), ?????NULL}, ?????//?啟用accept_mutex負(fù)載均衡鎖后,延遲accept_mutex_delay毫秒后再試圖處理新連接事件 ????{ngx_string("accept_mutex_delay"), ?????NGX_EVENT_CONF?|?NGX_CONF_TAKE1, ?????ngx_conf_set_msec_slot, ?????0, ?????offsetof(ngx_event_conf_t,?accept_mutex_delay), ?????NULL}, ?????//?需要對來自指定IP的TCP連接打印debug級別的調(diào)試日志 ????{ngx_string("debug_connection"), ?????NGX_EVENT_CONF?|?NGX_CONF_TAKE1, ?????ngx_event_debug_connection, ?????0, ?????0, ?????NULL}, ????ngx_null_command };

在事件模塊的定義中,module context指向的是一個ngx_event_module_t結(jié)構(gòu)體,這里的ngx_event_core_module的module context指向的就是第二個結(jié)構(gòu)體定義的ngx_event_core_module_ctx,而ngx_event_core_module_ctx中則定義了當(dāng)前核心模塊創(chuàng)建配置對象和初始化配置對象的方法,可以看到,其actions屬性中的值全部為NULL,這是因為該模塊并不負(fù)責(zé)處理具體的事件處理方案,而是負(fù)責(zé)核心結(jié)構(gòu)體的創(chuàng)建和初始化,nginx也會保證這個模塊在所有的事件模塊中最先被調(diào)用,其余各個事件模塊也可以引用該模塊所存儲的基礎(chǔ)配置數(shù)據(jù)。

在ngx_event_core_module中第三個屬性ngx_event_core_commands指向的是上面的第三個結(jié)構(gòu)體,這個結(jié)構(gòu)體中定義了當(dāng)前事件模塊所能使用的各個配置項的基本配置以及解析這些配置項的方法。

這里我們需要著重強(qiáng)調(diào)ngx_event_core_module中的第六個和第七個屬性,這兩個屬性指向的是都是某個方法,第六個屬性init module的主要是在nginx啟動過程中解析完nginx.conf配置文件之后執(zhí)行,其作用是對當(dāng)前模塊進(jìn)行初始化的工作,而第七個屬性init process主要是在nginx啟動worker進(jìn)程之后worker進(jìn)程開始執(zhí)行主循環(huán)之前調(diào)用的,其作用是進(jìn)行worker進(jìn)程執(zhí)行前的初始化工作。

3. 模塊方法的執(zhí)行流程

通過上面的介紹我們大致了解了定義事件模塊的兩個核心模塊的主要方法及其作用,這里則主要是對這些方法的執(zhí)行流程進(jìn)行講解,如下是其流程示意圖:

關(guān)于nginx事件模塊結(jié)構(gòu)體的詳解

?對于上面的,這里需要對其各個步驟的功能進(jìn)行說明:

1.解析nginx.conf文件,當(dāng)遇到events配置項時,就使用ngx_evetns_block()方法對其進(jìn)行解析;

2.創(chuàng)建用于存儲各個事件模塊存儲配置項的結(jié)構(gòu)體的數(shù)組;

3.采用遞歸的方式解析events配置塊中的子配置項;

4.依次檢查事件核心模塊的配置項,如果其沒有賦值,則對其賦一個默認(rèn)值;

5.檢查是否創(chuàng)建了存儲事件模塊配置項的數(shù)組,該檢查的主要目的是判斷核心模塊是否成功初始化了;

6.主要是通過解析得到的配置項,設(shè)置諸如時間定時器的執(zhí)行頻率、可打開的文件句柄限制和初始化記錄統(tǒng)計數(shù)據(jù)的屬性;

7.在worker進(jìn)程中調(diào)用,用于初始化worker進(jìn)程運(yùn)行所需要的環(huán)境,比如初始化事件隊列、初始化事件模型、添加時間更新的定時任務(wù)等;

以上就是關(guān)于

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點贊14 分享