이벤트 모듈은 nginx의 핵심 모듈 중 하나입니다. nginx의 클라이언트 요청 처리 및 명령줄 명령 실행은 이벤트 모듈에 의해 이루어집니다. 따라서 이벤트 모듈의 구현 원리를 익히는 것은 nginx의 전체 아키텍처를 이해하는 데 매우 중요합니다.
이 글에서는 먼저 여러 모듈 정의와 이벤트 모듈과 관련된 실행 프로세스에 대해 설명하겠습니다. 소스 코드는 이후 글에서 설명하겠습니다.
추천 튜토리얼: Nginx 튜토리얼
nginx에는 주로 ngx_events_module
및 ngx_event_core_module
이라는 두 가지 이벤트 코어 모듈이 있습니다. 이 두 모듈의 주요 차이점은 ngx_events_module의 유형이 NGX_CORE_MODULE
라는 것입니다. 이는 본질적으로 핵심 모듈 유형이지만 이벤트 모듈의 구문 분석된 구성 항목은 이벤트입니다. ngx_events_module
和ngx_event_core_module
。这两个模块的主要区别在于,ngx_events_module的类型为NGX_CORE_MODULE
,其本质上虽然是核心模块类型,但是却是事件模块的一个驱动点,其解析的配置项为events {},并且会创建用于存储事件模块相关配置的结构体;
而ngx_event_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 context指向的是ngx_events_module_ctx
,也即第二个结构体的配置,而module directives指向的则是ngx_events_commands
,也即第三个结构体的定义。可以看到,ngx_events_commands
中只定义了一个events配置项,而这个配置项的类型为NGX_CONF_BLOCK,也就是说其是一个配置块的类型,这里我们就理解了,这个command对应的就是我们在nginx.conf中使用的events {}配置块,而这个配置块的解析则是通过ngx_events_block()
方法进行的。
我们知道,在nginx的核心配置对象ngx_cycle_t中的conf_ctx数组中,每个模块在数组对应的位置都会有一个配置对象,同理,这里的核心模块也会有一个配置对象,但是上面的第二个结构体ngx_events_module_ctx
中的第二个属性值为NULL,也就是说这里的事件模块的定义中是没有创建配置对象的方法的,但是却有初始化配置对象的方法,也即第三个属性值ngx_event_init_conf()
方法。
那么这里事件模块的配置对象是在哪里创建的呢?
其实其就是在解析配置对象的时候进行的,也即在执行解析events {}
配置块的ngx_events_block()
方法中进行的。该方法本质上只是创建了一个指针数组,然后将其赋值给nginx核心和值对象的ngx_cycle_t的conf_ctx的对应位置。
2. ngx_event_core_module
在介绍ngx_event_core_module
模块之前,我们首先需要讲解一下事件模块的接口定义:
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;
nginx的事件模块主要有两个配置结构体:ngx_event_module_t
和ngx_event_actions_t
两个。从上面的定义中可以看出,ngx_event_module_t
结构体是引用了ngx_event_actions_t
的。
ngx_event_module_t
的作用主要是创建和初始化当前模块所需要的配置结构体,而ngx_event_actions_t则主要定义了当前事件模块处理各个事件的方式,这个接口典型的实现接口是nginx定义的各个事件模型,比如epoll的ngx_epoll_module_ctx.actions
和kqueue的ngx_kqueue_module_ctx.actions
。从这里就可以看出,事件模块的定义抽象了各个处理事件的模型的相关处理方法。
对于事件模块而言,其有一个模块是用于存储事件相关的基础配置的,即ngx_event_core_module
,虽然实现了ngx_event_module_t
接口,但是其不进行具体的事件处理。如下是ngx_event_core_module
NGX_EVENT_MODULE
이며, 이 모듈의 구성 개체는 이벤트 모듈의 기본 구성 개체를 저장합니다. 주요 기능은 파싱되는 이벤트 구성 블록의 하위 구성 항목입니다.{} 🎜🎜이 두 모듈의 기본 구성을 살펴보겠습니다. 🎜🎜1.ngx_events_module🎜🎜🎜 다음은 ngx_events_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进程启动的过程中调用的,用于初始化时间模块 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 };
ngx_events_module
모듈 정의에서 해당 모듈 컨텍스트는 ngx_events_module_ctx<를 가리킵니다. /code> 즉, 두 번째 구조의 구성이고 모듈 지시문은 세 번째 구조의 정의인 <code>ngx_events_commands
를 가리킵니다. ngx_events_commands
에는 이벤트 구성 항목이 하나만 정의되어 있음을 알 수 있으며, 이 구성 항목의 유형은 NGX_CONF_BLOCK으로 구성 블록 유형임을 의미합니다. nginx.conf에서 사용하는 이벤트 {} 구성 블록이며, 이 구성 블록의 구문 분석은 ngx_events_block()
메서드를 통해 수행됩니다. 🎜🎜우리는 nginx의 핵심 구성 개체 ngx_cycle_t의 conf_ctx 배열에서 각 모듈이 배열의 해당 위치에 구성 개체를 갖게 된다는 것을 알고 있습니다. 마찬가지로 여기의 핵심 모듈에도 구성 개체가 있지만 위의 두 번째 속성은 다음과 같습니다. 두 구조체 ngx_events_module_ctx
의 값이 NULL입니다. 즉, 여기서 이벤트 모듈의 정의에는 구성 개체를 생성하는 메서드가 없지만 구성 개체를 초기화하는 메서드가 있다는 의미입니다. , 세 번째 속성 값 ngx_event_init_conf()
메서드. 🎜🎜그럼 여기서 생성된 이벤트 모듈의 구성 객체는 어디에 있나요? 🎜🎜🎜실제로는 구성 객체를 파싱할 때, 즉 events{}
구성 블록을 파싱하는 ngx_events_block()
메서드를 실행할 때 수행됩니다. 이 방법은 본질적으로 포인터 배열을 생성하고 이를 nginx 코어와 값 개체의 ngx_cycle_t에 있는 conf_ctx의 해당 위치에 할당합니다. 🎜🎜2.ngx_event_core_module🎜🎜🎜ngx_event_core_module
모듈을 소개하기 전에 먼저 이벤트 모듈의 인터페이스 정의를 설명해야 합니다. 🎜rrreee🎜 nginx의 이벤트 모듈에는 크게 두 가지 구성 구조가 있습니다. : 2개: ngx_event_module_t
및 ngx_event_actions_t
. 위 정의에서 볼 수 있듯이 ngx_event_module_t
구조는 ngx_event_actions_t
를 참조합니다. 🎜🎜ngx_event_module_t
는 현재 모듈에 필요한 구성 구조를 생성하고 초기화하는 데 주로 사용되는 반면, ngx_event_actions_t는 주로 현재 이벤트 모듈이 각 이벤트를 처리하는 방식을 정의합니다. 이 인터페이스의 일반적인 구현 인터페이스는 다음과 같이 정의됩니다. nginx epoll의 ngx_epoll_module_ctx.actions
및 kqueue의 ngx_kqueue_module_ctx.actions
와 같은 다양한 이벤트 모델. 여기에서 이벤트 모듈의 정의는 각 이벤트 처리 모델의 관련 처리 방법을 추상화한다는 것을 알 수 있습니다. 🎜🎜이벤트 모듈에는 이벤트와 관련된 기본 구성을 저장하는 데 사용되는 모듈, 즉 ngx_event_core_module
이 있습니다. ngx_event_module_t
인터페이스를 구현하지만 특정 이벤트 처리를 수행하지는 않습니다. . 다음은 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进程启动的过程中调用的,用于初始化时间模块 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 };
在事件模块的定义中,module context指向的是一个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 중국어 웹사이트의 기타 관련 기사를 참조하세요!