イベント モジュール は、nginx のコア モジュールの 1 つであり、nginx でのクライアント リクエストの処理とコマンド ライン命令の実行は、イベント モジュールによって駆動されます。したがって、イベントモジュールの実装原理をマスターすることは、nginx の全体的なアーキテクチャを理解する上で非常に重要です。
この記事では、まずイベント モジュールとその実行プロセスに関連するいくつかのモジュール定義とそのソース コードについて説明します。 . 後の記事で行います。 推奨チュートリアル: nginx には主に、
ngx_events_module と
ngx_event_core_module という 2 つのイベント コア モジュールがあります。これら 2 つのモジュールの主な違いは、ngx_events_module のタイプが
NGX_CORE_MODULE であることです。これは本質的にコア モジュール タイプですが、イベント モジュールの駆動ポイントです。その解析された構成アイテムはイベント {} です。イベント モジュールの関連構成を保存するための構造体が作成されます。
NGX_EVENT_MODULE です。イベント モジュールの基本構成オブジェクトは構成オブジェクトに保存されますこのモジュールの主な機能は、events{} 設定ブロック内のサブ設定項目を解析することです。
1. ngx_events_module
以下は、ngx_events_module モジュールの基本構成です: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, its モジュール コンテキストは ngx_events_module_ctx
(2 番目の構造の構成) を指し、モジュール ディレクティブは ngx_events_commands
(3 番目の構造の定義) を指します。 ngx_events_commands
にはイベント設定項目が 1 つだけ定義されていることがわかり、この設定項目のタイプは NGX_CONF_BLOCK であり、これは設定ブロック タイプであることを意味します。は、nginx.conf で使用する events {} 構成ブロックであり、この構成ブロックの解析は ngx_events_block()
メソッドを通じて実行されます。 nginx コア構成オブジェクト ngx_cycle_t の conf_ctx 配列では、各モジュールが配列の対応する位置に構成オブジェクトを持つことがわかります。同様に、ここのコア モジュールにも構成オブジェクトがあります。上記の 2 番目の構造体
の 2 番目の属性値は NULL です。これは、ここのイベント モジュールの定義に構成オブジェクトを作成するメソッドはありませんが、構成オブジェクトを初期化する方法はあることを意味します。 .メソッド、つまり 3 番目の属性値 ngx_event_init_conf()
メソッドです。
実際には、これは構成オブジェクトを解析するときに実行されます。つまり、
events {} 構成ブロックを解析する ngx_events_block()
メソッドで実行されます。 。 の。このメソッドは基本的にポインターの配列を作成し、それを nginx コアと値オブジェクトの ngx_cycle_t の conf_ctx の対応する場所に割り当てるだけです。
ngx_event_core_module
モジュールを紹介する前に、まずイベント モジュールのインターフェイス定義について説明する必要があります: <pre class="brush:php;toolbar:false">typedef struct {
// 事件模块的名称
ngx_str_t *name;
// 在解析配置项前,这个回调方法用于创建存储配置项参数的结构体
void *(*create_conf)(ngx_cycle_t *cycle);
// 在解析配置项完成后,init_conf()方法会被调用,用以综合处理当前事件模块感兴趣的全部配置项
char *(*init_conf)(ngx_cycle_t *cycle, void *conf);
// 对于事件驱动机制,每个事件模块需要实现的10个抽象方法
ngx_event_actions_t actions;
} ngx_event_module_t;
typedef struct {
// 添加事件方法,它负责把一个感兴趣的事件添加到操作系统提供的事件驱动机制(epoll、kqueue等)中,
// 这样,在事件发生后,将可以在调用下面的process_events时获取这个事件
ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
// 删除事件方法,它把一个已经存在于事件驱动机制中的事件移除,这样以后即使这个事件发生,
// 调用process_events()方法时也无法再获取这个事件
ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
// 启用一个事件,目前事件框架不会调用这个方法,大部分事件驱动模块对于该方法的实现都是
// 与上面的add()方法完全一致的
ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
// 禁用一个事件,目前事件框架不会调用这个方法,大部分事件驱动模块对于该方法的实现都是
// 与上面的del()方法完全一致的
ngx_int_t (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
// 向事件驱动机制中添加一个新的连接,这意味着连接上的读写事件都添加到事件驱动机制中了
ngx_int_t (*add_conn)(ngx_connection_t *c);
// 从事件驱动机制中移除一个连接的读写事件
ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);
ngx_int_t (*notify)(ngx_event_handler_pt handler);
// 在正常的工作循环中,将通过调用process_events()方法来处理事件。
// 这个方法仅在ngx_process_events_and_timers()方法中调用,它是处理、分发事件的核心
ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags);
// 初始化事件驱动模块的方法
ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);
// 退出事件驱动模块前调用的方法
void (*done)(ngx_cycle_t *cycle);
} ngx_event_actions_t;</pre>
nginx のイベント モジュールには、主に
と ngx_event_actions_t
という 2 つの構成構造があります。上記の定義からわかるように、ngx_event_module_t
構造は ngx_event_actions_t
を参照します。
は主に現在のモジュールに必要な構成構造の作成と初期化に使用され、ngx_event_actions_t は主に現在のイベント モジュールが各イベントを処理する方法を定義します。このインターフェイスは典型的な実装インターフェイスです。これらは、epoll の ngx_epoll_module_ctx.actions
や kqueue の ngx_kqueue_module_ctx.actions
など、nginx によって定義されたさまざまなイベント モデルです。ここから、イベント モジュールの定義が各イベント処理モデルの関連する処理メソッドを抽象化していることがわかります。 イベント モジュールには、イベントに関連する基本構成を保存するために使用されるモジュール、つまり
があります。ngx_event_module_t
インターフェイスが実装されていますが、その具体的な機能はありませんイベント処理が行われます。以下は ngx_event_core_module
モジュールの定義です: <pre class="brush:php;toolbar:false">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进程启动的过程中调用的,用于初始化时间模块
ngx_event_module_init, /* init module */
// 该方法是在各个worker进程启动之后调用的
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并不直接负责TCP网络事件的驱动,
// 因而这里的ngx_event_actions_t中的方法都为NULL
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
};
static ngx_command_t ngx_event_core_commands[] = {
// 连接池的大小,也即每个worker进程中支持的TCP最大连接数,它与connections配置项的意义是重复的
{ngx_string("worker_connections"),
NGX_EVENT_CONF | NGX_CONF_TAKE1,
ngx_event_connections,
0,
0,
NULL},
// 确定选择哪一个事件模块作为事件驱动机制
{ngx_string("use"),
NGX_EVENT_CONF | NGX_CONF_TAKE1,
ngx_event_use,
0,
0,
NULL},
// 对应于ngx_event_s中的available属性,对于epoll事件驱动模式来说,意味着在接收到一个新连接事件时,
// 调用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负载均衡锁,默认为开启
{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负载均衡锁后,延迟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级别的调试日志
{ngx_string("debug_connection"),
NGX_EVENT_CONF | NGX_CONF_TAKE1,
ngx_event_debug_connection,
0,
0,
NULL},
ngx_null_command
};</pre><p>在事件模块的定义中,module context指向的是一个<code>ngx_event_module_t
结构体,这里的ngx_event_core_module
的module context指向的就是第二个结构体定义的ngx_event_core_module_ctx
,而ngx_event_core_module_ctx
中则定义了当前核心模块创建配置对象和初始化配置对象的方法,可以看到,其actions属性中的值全部为NULL,这是因为该模块并不负责处理具体的事件处理方案,而是负责核心结构体的创建和初始化,nginx也会保证这个模块在所有的事件模块中最先被调用,其余各个事件模块也可以引用该模块所存储的基础配置数据。
在ngx_event_core_module
中第三个属性ngx_event_core_commands
指向的是上面的第三个结构体,这个结构体中定义了当前事件模块所能使用的各个配置项的基本配置以及解析这些配置项的方法。
这里我们需要着重强调ngx_event_core_module
中的第六个和第七个属性,这两个属性指向的是都是某个方法,第六个属性init module的主要是在nginx启动过程中解析完nginx.conf
配置文件之后执行,其作用是对当前模块进行初始化的工作,而第七个属性init process主要是在nginx启动worker进程之后worker进程开始执行主循环之前调用的,其作用是进行worker进程执行前的初始化工作。
3. 模块方法的执行流程
通过上面的介绍我们大致了解了定义事件模块的两个核心模块的主要方法及其作用,这里则主要是对这些方法的执行流程进行讲解,如下是其流程示意图:
对于上面的,这里需要对其各个步骤的功能进行说明:
1.解析nginx.conf
文件,当遇到events
配置项时,就使用ngx_evetns_block()
方法对其进行解析;
2.创建用于存储各个事件模块存储配置项的结构体的数组;
3.采用递归的方式解析events
配置块中的子配置项;
4.依次检查事件核心模块的配置项,如果其没有赋值,则对其赋一个默认值;
5.检查是否创建了存储事件模块配置项的数组,该检查的主要目的是判断核心模块是否成功初始化了;
6.主要是通过解析得到的配置项,设置诸如时间定时器的执行频率、可打开的文件句柄限制和初始化记录统计数据的属性;
7.在worker
进程中调用,用于初始化worker
进程运行所需要的环境,比如初始化事件队列、初始化事件模型、添加时间更新的定时任务等;
以上がnginxイベントモジュール構造の詳しい説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。