Übersicht
Nginx wird durch das Auslösen von Ereignissen gesteuert. Das ereignisgesteuerte Modell umfasst hauptsächlich drei Teile: Ereigniserfassung, Ereignisversand und Ereignisverarbeitung (d. h. Ereignisverwaltung). Die wichtigsten Ereignisse von Interesse im Arbeitsprozess von Nginx sind IO Netzwerkereignisse und Timerereignisse. In der generierten Verzeichnisdatei objs befindet sich der Inhalt der Datei ngx_modules.c Nginx Die Ausführungsreihenfolge verschiedener Module Aus dem Inhalt dieser Datei können wir ersehen, dass die Ausführungsreihenfolge des Ereignismoduls wie folgt ist: Hinweis: Da dies der Fall ist Linux-System, daher unterstützt es das spezifische epoll-Ereignismodul. Die Struktur des nächsten Artikels ist in der folgenden Reihenfolge geschrieben.
extern ngx_module_t ngx_events_module; extern ngx_module_t ngx_event_core_module; extern ngx_module_t ngx_epoll_module;
Ereignismodulschnittstelle
ngx_event_module_t Struktur
In Nginx ist Strukturngx_module_t die grundlegendste Schnittstelle des Nginx-Moduls. Für jeden Modultyp gibt es eine spezifische Struktur zur Beschreibung der gemeinsamen Schnittstelle dieses Modultyps, die aus Mitgliedern in ngx_module_t besteht ctx Management. Die allgemeine Schnittstellenstruktur ngx_event_module_t des Ereignismoduls ist in Nginx definiert, die in der Datei src/event/ngx_event.h definiert ist:
/* 事件驱动模型通用接口ngx_event_module_t结构体 */ typedef struct { /* 事件模块名称 */ ngx_str_t *name; /* 解析配置项前调用,创建存储配置项参数的结构体 */ void *(*create_conf)(ngx_cycle_t *cycle); /* 完成配置项解析后调用,处理当前事件模块感兴趣的全部配置 */ char *(*init_conf)(ngx_cycle_t *cycle, void *conf); /* 每个事件模块具体实现的方法,有10个方法,即IO多路复用模型的统一接口 */ ngx_event_actions_t actions; } ngx_event_module_t;
Der Typ der Aktionen in der ngx_event_module_t-Struktur ist ngx_event_actions_t Struktur, diese Mitgliedsstruktur implementiert die spezifischen Methoden des ereignisgesteuerten Moduls. Diese Struktur ist in der Datei definiert src/event/ngx_event.h:
/* IO多路复用模型的统一接口 */ typedef struct { /* 添加事件,将某个描述符的某个事件添加到事件驱动机制监控描述符集中 */ ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); /* 删除事件,将某个描述符的某个事件从事件驱动机制监控描述符集中删除 */ ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); /* 启动对某个指定事件的监控 */ ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); /* 禁用对某个指定事件的监控 */ 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 (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait); /* 等待事件的发生,并对事件进行处理 */ 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;
ngx_event_t Struktur
In Nginx jeweils Die Definition von Ein bestimmtes Ereignis wird durch die Struktur ngx_event_t dargestellt, die ngx_event_t wird zum Speichern bestimmter Ereignisse verwendet. Diese Struktur ist in der Datei definiert src/event/ngx_event.h:
/* 描述每一个事件的ngx_event_t结构体 */ struct ngx_event_s { /* 事件相关对象的数据,通常指向ngx_connect_t连接对象 */ void *data; /* 标志位,为1表示事件可写,即当前对应的TCP连接状态可写 */ unsigned write:1; /* 标志位,为1表示事件可以建立新连接 */ unsigned accept:1; /* used to detect the stale events in kqueue, rtsig, and epoll */ unsigned instance:1; /* * the event was passed or would be passed to a kernel; * in aio mode - operation was posted. */ /* 标志位,为1表示事件处于活跃状态 */ unsigned active:1; /* 标志位,为1表示禁用事件 */ unsigned disabled:1; /* the ready event; in aio mode 0 means that no operation can be posted */ /* 标志位,为1表示当前事件已经准备就绪 */ unsigned ready:1; /* 该标志位只用于kqueue,eventport模块,对Linux上的驱动模块没有任何意义 */ unsigned oneshot:1; /* aio operation is complete */ /* 该标志位用于异步AIO事件处理 */ unsigned complete:1; /* 标志位,为1表示当前处理的字符流已经结束 */ unsigned eof:1; /* 标志位,为1表示当前事件处理过程中出错 */ unsigned error:1; /* 标志位,为1表示当前事件已超时 */ unsigned timedout:1; /* 标志位,为1表示当前事件存在于定时器中 */ unsigned timer_set:1; /* 标志位,为1表示当前事件需要延迟处理 */ unsigned delayed:1; /* * 标志位,为1表示TCP建立需要延迟,即完成建立TCP连接的三次握手后, * 不会立即建立TCP连接,直到接收到数据包才建立TCP连接; */ unsigned deferred_accept:1; /* the pending eof reported by kqueue, epoll or in aio chain operation */ /* 标志位,为1表示等待字符流结束 */ unsigned pending_eof:1; /* 标志位,为1表示处理post事件 */ unsigned posted:1; #if (NGX_WIN32) /* setsockopt(SO_UPDATE_ACCEPT_CONTEXT) was successful */ unsigned accept_context_updated:1; #endif #if (NGX_HAVE_KQUEUE) unsigned kq_vnode:1; /* the pending errno reported by kqueue */ int kq_errno; #endif /* * kqueue only: * accept: number of sockets that wait to be accepted * read: bytes to read when event is ready * or lowat when event is set with NGX_LOWAT_EVENT flag * write: available space in buffer when event is ready * or lowat when event is set with NGX_LOWAT_EVENT flag * * iocp: TODO * * otherwise: * accept: 1 if accept many, 0 otherwise */ #if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP) int available; #else /* 标志位,在epoll事件机制中表示一次尽可能多地建立TCP连接 */ unsigned available:1; #endif /* 当前事件发生时的处理方法 */ ngx_event_handler_pt handler; #if (NGX_HAVE_AIO) #if (NGX_HAVE_IOCP) ngx_event_ovlp_t ovlp; #else /* Linux系统aio机制中定义的结构体 */ struct aiocb aiocb; #endif #endif /* epoll机制不使用该变量 */ ngx_uint_t index; /* 日志记录 */ ngx_log_t *log; /* 定时器 */ ngx_rbtree_node_t timer; /* the posted queue */ ngx_queue_t queue; /* 标志位,为1表示当前事件已经关闭 */ unsigned closed:1; /* to test on worker exit */ unsigned channel:1; unsigned resolver:1; unsigned cancelable:1; #if 0 /* the threads support */ /* * the event thread context, we store it here * if $(CC) does not understand __thread declaration * and pthread_getspecific() is too costly */ void *thr_ctx; #if (NGX_EVENT_T_PADDING) /* event should not cross cache line in SMP */ uint32_t padding[NGX_EVENT_T_PADDING]; #endif #endif };
In jeder Ereignisstruktur ngx_event_t ist das wichtigste Mitglied die Callback-Funktion handler, Die Rückruffunktion definiert die Verarbeitungsmethode, wenn das Ereignis auftritt. Der Prototyp der Rückrufmethode befindet sich in der Datei src/core/ngx_core.h:
typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);
ngx_connection_t Struktur
Wenn der Client Nginx-Server eine Verbindungsanforderung initiiert und der Nginx-Server die Verbindung passiv empfängt, wird dies der Fall sein Nginx wird als passive Verbindung für den Server bezeichnet. Die passive Verbindung wird durch die grundlegende Datenstruktur dargestellt ngx_connection_t Fertig. Diese Struktur ist in der Datei definiert src/core/ngx_connection.h Medium:
/* TCP连接结构体 */ struct ngx_connection_s { /* * 当Nginx服务器产生新的socket时, * 都会创建一个ngx_connection_s 结构体, * 该结构体用于保存socket的属性和数据; */ /* * 当连接未被使用时,data充当连接池中空闲连接表中的next指针; * 当连接被使用时,data的意义由具体Nginx模块决定; */ void *data; /* 设置该链接的读事件 */ ngx_event_t *read; /* 设置该连接的写事件 */ ngx_event_t *write; /* 用于设置socket的套接字描述符 */ ngx_socket_t fd; /* 接收网络字符流的方法,是一个函数指针,指向接收函数 */ ngx_recv_pt recv; /* 发送网络字符流的方法,是一个函数指针,指向发送函数 */ ngx_send_pt send; /* 以ngx_chain_t链表方式接收网络字符流的方法 */ ngx_recv_chain_pt recv_chain; /* 以ngx_chain_t链表方式发送网络字符流的方法 */ ngx_send_chain_pt send_chain; /* * 当前连接对应的ngx_listening_t监听对象, * 当前连接由ngx_listening_t成员的listening监听端口的事件建立; * 成员connection指向当前连接; */ ngx_listening_t *listening; /* 当前连接已发生的字节数 */ off_t sent; /* 记录日志 */ ngx_log_t *log; /* 内存池 */ ngx_pool_t *pool; /* 对端的socket地址sockaddr属性*/ struct sockaddr *sockaddr; socklen_t socklen; /* 字符串形式的IP地址 */ ngx_str_t addr_text; ngx_str_t proxy_protocol_addr; #if (NGX_SSL) ngx_ssl_connection_t *ssl; #endif /* 本端的监听端口对应的socket的地址sockaddr属性 */ struct sockaddr *local_sockaddr; socklen_t local_socklen; /* 用于接收、缓存对端发来的字符流 */ ngx_buf_t *buffer; /* * 表示将当前连接作为双向连接中节点元素, * 添加到ngx_cycle_t结构体的成员 * reuseable_connections_queue的双向链表中; */ ngx_queue_t queue; /* 连接使用次数 */ ngx_atomic_uint_t number; /* 处理请求的次数 */ ngx_uint_t requests; unsigned buffered:8; unsigned log_error:3; /* ngx_connection_log_error_e */ /* 标志位,为1表示不期待字符流结束 */ unsigned unexpected_eof:1; /* 标志位,为1表示当前连接已经超时 */ unsigned timedout:1; /* 标志位,为1表示处理连接过程出错 */ unsigned error:1; /* 标志位,为1表示当前TCP连接已经销毁 */ unsigned destroyed:1; /* 标志位,为1表示当前连接处于空闲状态 */ unsigned idle:1; /* 标志位,为1表示当前连接可重用 */ unsigned reusable:1; /* 标志为,为1表示当前连接已经关闭 */ unsigned close:1; /* 标志位,为1表示正在将文件的数据发往对端 */ unsigned sendfile:1; /* * 标志位,若为1,则表示只有连接对应的发送缓冲区满足最低设置的阈值时, * 事件驱动模块才会分发事件; */ unsigned sndlowat:1; unsigned tcp_nodelay:2; /* ngx_connection_tcp_nodelay_e */ unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */ unsigned need_last_buf:1; #if (NGX_HAVE_IOCP) unsigned accept_context_updated:1; #endif #if (NGX_HAVE_AIO_SENDFILE) /* 标志位,为1表示使用异步IO方式将磁盘文件发送给网络连接的对端 */ unsigned aio_sendfile:1; unsigned busy_count:2; /* 使用异步IO发送文件时,用于待发送的文件信息 */ ngx_buf_t *busy_sendfile; #endif #if (NGX_THREADS) ngx_atomic_t lock; #endif };
Nginx-Server aktiv eine Verbindung zum Upstream-Server herstellt , der Verbindungsaufbau ist abgeschlossen und die Kommunikation mit dem Nginx-Server ist eine aktive Verbindung ngx_peer_connection_t repräsentiert, aber die Struktur ngx_peer_connection_t ist auch eine Kapselung der ngx_connection_t-Struktur. Die Struktur ist in der Datei src/event/ngx_event_connect.h definiert:
/* 主动连接的结构体 */ struct ngx_peer_connection_s { /* 这里是对ngx_connection_t连接结构体的引用 */ ngx_connection_t *connection; /* 远端服务器的socket的地址sockaddr信息 */ struct sockaddr *sockaddr; socklen_t socklen; /* 远端服务器的名称 */ ngx_str_t *name; /* 连接重试的次数 */ ngx_uint_t tries; /* 获取连接的方法 */ ngx_event_get_peer_pt get; /* 释放连接的方法 */ ngx_event_free_peer_pt free; /* 配合get、free使用 */ void *data; #if (NGX_SSL) ngx_event_set_peer_session_pt set_session; ngx_event_save_peer_session_pt save_session; #endif #if (NGX_THREADS) ngx_atomic_t *lock; #endif /* 本地地址信息 */ ngx_addr_t *local; /* 接收缓冲区 */ int rcvbuf; /* 记录日志 */ ngx_log_t *log; /* 标志位,为1表示connection连接已经缓存 */ unsigned cached:1; /* ngx_connection_log_error_e */ unsigned log_error:2; };
ngx_events_module Kernmodul
ngx_events_module Definition des Kernmoduls
ngx_events_module Modul ist das Kernmodul von Ereignissen. Die Funktion dieses Moduls besteht darin, neue Ereignistypen zu definieren und eine gemeinsame Schnittstelle für jedes Ereignismodul zu definieren Die Struktur ngx_event_module_t verwaltet die vom Ereignismodul generierte Konfigurationselementstruktur und analysiert die Konfigurationselemente der Ereignisklasse. Schauen Sie sich zunächst die Definition des Moduls in der Datei src/event/ngx_event.c an:
/* 定义事件核心模块 */ 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 };
ngx_events_commands ist die bestimmte Funktion dieses Moduls. Befehlsstruktur des Konfigurationselementsngx_events_commands in der Datei src/event/ngx_event.c ist wie folgt definiert:
/* 配置项结构体数组 */ 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 };
Ereignisse{...} unterstützt. Konfigurationsblöcke sind von Interesse und definieren Methoden zur Verwaltung von Ereignismodulen ngx_events_block; ngx_events_block Methoden werden in der Datei src/event/ngx_event.c definiert: >
Darüber hinaus gibt es in der Definition des Moduls/* 管理事件模块 */ static char * ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; void ***ctx; ngx_uint_t i; ngx_conf_t pcf; ngx_event_module_t *m; if (*(void **) conf) { return "is duplicate"; } /* count the number of the event modules and set up their indices */ /* 计算模块类中模块的总数,并初始化模块在模块类中的序号 */ 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++; } ctx = ngx_pcalloc(cf->pool, sizeof(void *)); if (ctx == NULL) { return NGX_CONF_ERROR; } /* 分配指针数组,用于存储所有事件模块生成的配置项结构体指针 */ *ctx = ngx_pcalloc(cf->pool, ngx_event_max_module * sizeof(void *)); if (*ctx == NULL) { return NGX_CONF_ERROR; } *(void **) conf = ctx; /* 若是事件模块,并且定义了create_conf方法,则调用该方法创建存储配置项参数的结构体 */ for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_EVENT_MODULE) { continue; } m = ngx_modules[i]->ctx; if (m->create_conf) { (*ctx)[ngx_modules[i]->ctx_index] = m->create_conf(cf->cycle); if ((*ctx)[ngx_modules[i]->ctx_index] == NULL) { return NGX_CONF_ERROR; } } } /* 初始化配置项结构体cf */ pcf = *cf; cf->ctx = ctx;/* 描述事件模块的配置项结构 */ cf->module_type = NGX_EVENT_MODULE;/* 当前解析指令的模块类型 */ cf->cmd_type = NGX_EVENT_CONF;/* 当前解析指令的指令类型 */ /* 为所有事件模块解析配置文件nginx.conf中的event{}块中的指令 */ rv = ngx_conf_parse(cf, NULL); *cf = pcf; if (rv != NGX_CONF_OK) return rv; /* 遍历所有事件模块,若定义了init_conf方法,则调用该方法用于处理事件模块感兴趣的配置项 */ for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_EVENT_MODULE) { continue; } m = ngx_modules[i]->ctx; if (m->init_conf) { rv = m->init_conf(cf->cycle, (*ctx)[ngx_modules[i]->ctx_index]); if (rv != NGX_CONF_OK) { return rv; } } } return NGX_CONF_OK; }
ein Mitglied ctx, das auf die gemeinsame Schnittstellenstruktur des Kernmoduls verweist. Die allgemeine Schnittstellenstruktur des Kernmoduls ist in der Datei src/core/ngx_conf_file.h definiert:
Daher muss/* 核心模块的通用接口结构体 */ 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;
als Kernmodul gelten Definieren Sie den Kern. Die allgemeine Schnittstellenstruktur des Moduls. ngx_events_module Die gemeinsame Kernmodulschnittstelle des Moduls ist in der Datei src/event/ngx_event.c definiert:
Konfigurationselementverwaltung aller Ereignismodule/* 实现核心模块通用接口 */ static ngx_core_module_t ngx_events_module_ctx = { ngx_string("events"), NULL, /* * 以前的版本这里是NULL,现在实现了一个获取events配置项的函数,* * 但是没有什么作用,因为每个事件模块都会去获取events配置项, * 并进行解析与处理; */ ngx_event_init_conf };
Nginx 服务器在结构体 ngx_cycle_t 中定义了一个四级指针成员 conf_ctx,整个Nginx 模块都是使用该四级指针成员管理模块的配置项结构,以下events 模块为例对该四级指针成员进行简单的分析,如下图所示:
每个事件模块可以通过宏定义 ngx_event_get_conf 获取它在create_conf 中分配的结构体的指针;该宏中定义如下:
#define ngx_event_get_conf(conf_ctx, module) \ (*(ngx_get_conf(conf_ctx, ngx_events_module))) [module.ctx_index]; /* 其中 ngx_get_conf 定义如下 */ #define ngx_get_conf(conf_ctx, module) conf_ctx[module.index]
从上面的宏定义可以知道,每个事件模块获取自己在 create_conf 中分配的结构体的指针,只需在ngx_event_get_conf 传入参数 ngx_cycle_t 中的 conf_ctx 成员,并且传入自己模块的名称即可获取自己分配的结构体指针。
ngx_event_core_module 事件模块
ngx_event_core_module 模块是一个事件类型的模块,它在所有事件模块中的顺序是第一,是其它事件类模块的基础。它主要完成以下任务:
ngx_event_conf_t 结构体
ngx_event_conf_t 结构体是用来保存ngx_event_core_module 事件模块配置项参数的。该结构体在文件src/event/ngx_event.h 中定义:
/* 存储ngx_event_core_module事件模块配置项参数的结构体 ngx_event_conf_t */ typedef struct { /* 连接池中最大连接数 */ ngx_uint_t connections; /* 被选用模块在所有事件模块中的序号 */ ngx_uint_t use; /* 标志位,为1表示可批量建立连接 */ ngx_flag_t multi_accept; /* 标志位,为1表示打开负载均衡锁 */ ngx_flag_t accept_mutex; /* 延迟建立连接 */ ngx_msec_t accept_mutex_delay; /* 被使用事件模块的名称 */ u_char *name; #if (NGX_DEBUG) /* 用于保存与输出调试级别日志连接对应客户端的地址信息 */ ngx_array_t debug_connection; #endif } ngx_event_conf_t;
ngx_event_core_module 事件模块的定义
该模块在文件 src/event/ngx_event.c 中定义:
/* 事件模块的定义 */ 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 */ ngx_event_module_init, /* init module */ ngx_event_process_init, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING };
其中,模块的配置项指令结构
static ngx_str_t event_core_name = ngx_string("event_core"); /* 定义ngx_event_core_module 模块感兴趣的配置项 */ static ngx_command_t ngx_event_core_commands[] = { /* 每个worker进程中TCP最大连接数 */ { ngx_string("worker_connections"), NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_event_connections, 0, 0, NULL }, /* 与上面的worker_connections配置项相同 */ { ngx_string("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_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负载均衡锁后,延迟处理新连接事件 */ { 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_event_module_t,
/* 根据事件模块通用接口,实现ngx_event_core_module事件模块的上下文结构 */ 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 */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } };
在模块定义中,实现了两种方法分别为 ngx_event_module_init 和ngx_event_process_init 方法。在 Nginx 启动过程中没有使用 fork 出 worker 子进程之前,先调用 ngx_event_core_module 模块中的 ngx_event_module_init 方法,当fork 出 worker 子进程后,每一个 worker 子进程则会调用 ngx_event_process_init 方法。
ngx_event_module_init 方法在文件src/event/ngx_event.c 中定义:
/* 初始化事件模块 */ static ngx_int_t ngx_event_module_init(ngx_cycle_t *cycle) { void ***cf; u_char *shared; size_t size, cl; ngx_shm_t shm; ngx_time_t *tp; ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; /* 获取存储所有事件模块配置结构的指针数据的首地址 */ cf = ngx_get_conf(cycle->conf_ctx, ngx_events_module); /* 获取事件模块ngx_event_core_module的配置结构 */ ecf = (*cf)[ngx_event_core_module.ctx_index]; /* 在错误日志中输出被使用的事件模块名称 */ if (!ngx_test_config && ngx_process <= NGX_PROCESS_MASTER) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "using the \"%s\" event method", ecf->name); } /* 获取模块ngx_core_module的配置结构 */ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_timer_resolution = ccf->timer_resolution; #if !(NGX_WIN32) { ngx_int_t limit; struct rlimit rlmt; /* 获取当前进程所打开的最大文件描述符个数 */ if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "getrlimit(RLIMIT_NOFILE) failed, ignored"); } else { /* * 当前事件模块的连接数大于最大文件描述符个数, * 或者大于由配置文件nginx.conf指定的worker_rlinit_nofile设置的最大文件描述符个数时, * 出错返回; */ if (ecf->connections > (ngx_uint_t) rlmt.rlim_cur && (ccf->rlimit_nofile == NGX_CONF_UNSET || ecf->connections > (ngx_uint_t) ccf->rlimit_nofile)) { limit = (ccf->rlimit_nofile == NGX_CONF_UNSET) ? (ngx_int_t) rlmt.rlim_cur : ccf->rlimit_nofile; ngx_log_error(NGX_LOG_WARN, cycle->log, 0, "%ui worker_connections exceed " "open file resource limit: %i", ecf->connections, limit); } } } #endif /* !(NGX_WIN32) */ /* * 模块ngx_core_module的master进程为0,表示不创建worker进程, * 则初始化到此结束,并成功返回; */ if (ccf->master == 0) { return NGX_OK; } /* * 若master不为0,且存在负载均衡锁,则表示初始化完毕,并成功返回; */ if (ngx_accept_mutex_ptr) { return NGX_OK; } /* 不满足以上两个条件,则初始化下列变量 */ /* cl should be equal to or greater than cache line size */ /* 缓存行的大小 */ cl = 128; /* * 统计需要创建的共享内存大小; * ngx_accept_mutex用于多个worker进程之间的负载均衡锁; * ngx_connection_counter表示nginx处理的连接总数; * ngx_temp_number表示在连接中创建的临时文件个数; */ size = cl /* ngx_accept_mutex */ + cl /* ngx_connection_counter */ + cl; /* ngx_temp_number */ #if (NGX_STAT_STUB) /* * 下面表示某种情况的连接数; * ngx_stat_accepted 表示已成功建立的连接数; * ngx_stat_handled 表示已获取ngx_connection_t结构并已初始化读写事件的连接数; * ngx_stat_requests 表示已被http模块处理过的连接数; * ngx_stat_active 表示已获取ngx_connection_t结构体的连接数; * ngx_stat_reading 表示正在接收TCP字符流的连接数; * ngx_stat_writing 表示正在发送TCP字符流的连接数; * ngx_stat_waiting 表示正在等待事件发生的连接数; */ size += cl /* ngx_stat_accepted */ + cl /* ngx_stat_handled */ + cl /* ngx_stat_requests */ + cl /* ngx_stat_active */ + cl /* ngx_stat_reading */ + cl /* ngx_stat_writing */ + cl; /* ngx_stat_waiting */ #endif /* 初始化共享内存信息 */ shm.size = size; shm.name.len = sizeof("nginx_shared_zone"); shm.name.data = (u_char *) "nginx_shared_zone"; shm.log = cycle->log; /* 创建共享内存 */ if (ngx_shm_alloc(&shm) != NGX_OK) { return NGX_ERROR; } /* 获取共享内存的首地址 */ shared = shm.addr; ngx_accept_mutex_ptr = (ngx_atomic_t *) shared; /* -1表示以非阻塞模式获取共享内存锁 */ ngx_accept_mutex.spin = (ngx_uint_t) -1; if (ngx_shmtx_create(&ngx_accept_mutex, (ngx_shmtx_sh_t *) shared, cycle->lock_file.data) != NGX_OK) { return NGX_ERROR; } /* 初始化变量 */ ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * cl); (void) ngx_atomic_cmp_set(ngx_connection_counter, 0, 1); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "counter: %p, %d", ngx_connection_counter, *ngx_connection_counter); ngx_temp_number = (ngx_atomic_t *) (shared + 2 * cl); tp = ngx_timeofday(); ngx_random_number = (tp->msec << 16) + ngx_pid; #if (NGX_STAT_STUB) ngx_stat_accepted = (ngx_atomic_t *) (shared + 3 * cl); ngx_stat_handled = (ngx_atomic_t *) (shared + 4 * cl); ngx_stat_requests = (ngx_atomic_t *) (shared + 5 * cl); ngx_stat_active = (ngx_atomic_t *) (shared + 6 * cl); ngx_stat_reading = (ngx_atomic_t *) (shared + 7 * cl); ngx_stat_writing = (ngx_atomic_t *) (shared + 8 * cl); ngx_stat_waiting = (ngx_atomic_t *) (shared + 9 * cl); #endif return NGX_OK; }
ngx_event_process_init 方法在文件src/event/ngx_event.c 中定义:
static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle) { ngx_uint_t m, i; ngx_event_t *rev, *wev; ngx_listening_t *ls; ngx_connection_t *c, *next, *old; ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; ngx_event_module_t *module; /* 获取ngx_core_module核心模块的配置结构 */ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); /* 获取ngx_event_core_module事件核心模块的配置结构 */ ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); /* * 在事件核心模块启用accept_mutex锁的情况下, * 只有在master-worker工作模式并且worker进程数量大于1, * 此时,才确定进程启用负载均衡锁; */ if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) { ngx_use_accept_mutex = 1; ngx_accept_mutex_held = 0; ngx_accept_mutex_delay = ecf->accept_mutex_delay; } else {/* 否则关闭负载均衡锁 */ ngx_use_accept_mutex = 0; } #if (NGX_WIN32) /* * disable accept mutex on win32 as it may cause deadlock if * grabbed by a process which can't accept connections */ ngx_use_accept_mutex = 0; #endif ngx_queue_init(&ngx_posted_accept_events); ngx_queue_init(&ngx_posted_events); /* 初始化由红黑树实现的定时器 */ if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; } /* 根据use配置项所指定的事件模块,调用ngx_actions_t中的init方法初始化事件模块 */ for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_EVENT_MODULE) { continue; } if (ngx_modules[m]->ctx_index != ecf->use) { continue; } module = ngx_modules[m]->ctx; if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { /* fatal */ exit(2); } break; } #if !(NGX_WIN32) /* * NGX_USE_TIMER_EVENT只有在eventport和kqueue事件模型中使用, * 若配置文件nginx.conf设置了timer_resolution配置项, * 并且事件模型不为eventport和kqueue时,调用settimer方法, */ if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { struct sigaction sa; struct itimerval itv; ngx_memzero(&sa, sizeof(struct sigaction)); /* * ngx_timer_signal_handler的实现如下: * void ngx_timer_signal_handler(int signo) * { * ngx_event_timer_alarm = 1; * } * ngx_event_timer_alarm 为1时表示需要更新系统时间,即调用ngx_time_update方法; * 更新完系统时间之后,该变量设为0; */ /* 指定信号处理函数 */ sa.sa_handler = ngx_timer_signal_handler; /* 初始化信号集 */ sigemptyset(&sa.sa_mask); /* 捕获信号SIGALRM */ if (sigaction(SIGALRM, &sa, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigaction(SIGALRM) failed"); return NGX_ERROR; } /* 设置时间精度 */ itv.it_interval.tv_sec = ngx_timer_resolution / 1000; itv.it_interval.tv_usec = (ngx_timer_resolution % 1000) * 1000; itv.it_value.tv_sec = ngx_timer_resolution / 1000; itv.it_value.tv_usec = (ngx_timer_resolution % 1000 ) * 1000; /* 使用settimer函数发送信号 SIGALRM */ if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } /* 对poll、/dev/poll、rtsig事件模块的特殊处理 */ if (ngx_event_flags & NGX_USE_FD_EVENT) { struct rlimit rlmt; if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "getrlimit(RLIMIT_NOFILE) failed"); return NGX_ERROR; } cycle->files_n = (ngx_uint_t) rlmt.rlim_cur; cycle->files = ngx_calloc(sizeof(ngx_connection_t *) * cycle->files_n, cycle->log); if (cycle->files == NULL) { return NGX_ERROR; } } #endif /* 预分配连接池 */ cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log); if (cycle->connections == NULL) { return NGX_ERROR; } c = cycle->connections; /* 预分配读事件结构,读事件个数与连接数相同 */ cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->read_events == NULL) { return NGX_ERROR; } rev = cycle->read_events; for (i = 0; i < cycle->connection_n; i++) { rev[i].closed = 1; rev[i].instance = 1; } /* 预分配写事件结构,写事件个数与连接数相同 */ cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->write_events == NULL) { return NGX_ERROR; } wev = cycle->write_events; for (i = 0; i < cycle->connection_n; i++) { wev[i].closed = 1; } i = cycle->connection_n; next = NULL; /* 按照序号,将读、写事件与连接对象对应,即设置到每个ngx_connection_t 对象中 */ do { i--; c[i].data = next; c[i].read = &cycle->read_events[i]; c[i].write = &cycle->write_events[i]; c[i].fd = (ngx_socket_t) -1; next = &c[i]; #if (NGX_THREADS) c[i].lock = 0; #endif } while (i); /* 设置空闲连接链表 */ cycle->free_connections = next; cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ /* 为所有ngx_listening_t监听对象中的connections成员分配连接,并设置读事件的处理方法 */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { /* 为监听套接字分配连接,并设置读事件 */ c = ngx_get_connection(ls[i].fd, cycle->log); if (c == NULL) { return NGX_ERROR; } c->log = &ls[i].log; c->listening = &ls[i]; ls[i].connection = c; rev = c->read; rev->log = c->log; rev->accept = 1; #if (NGX_HAVE_DEFERRED_ACCEPT) rev->deferred_accept = ls[i].deferred_accept; #endif if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { if (ls[i].previous) { /* * delete the old accept events that were bound to * the old cycle read events array */ old = ls[i].previous->connection; if (ngx_del_event(old->read, NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) { return NGX_ERROR; } old->fd = (ngx_socket_t) -1; } } #if (NGX_WIN32) if (ngx_event_flags & NGX_USE_IOCP_EVENT) { ngx_iocp_conf_t *iocpcf; rev->handler = ngx_event_acceptex; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) { return NGX_ERROR; } ls[i].log.handler = ngx_acceptex_log_error; iocpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module); if (ngx_event_post_acceptex(&ls[i], iocpcf->post_acceptex) == NGX_ERROR) { return NGX_ERROR; } } else { rev->handler = ngx_event_accept; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #else /* 为监听端口的读事件设置处理方法ngx_event_accept */ rev->handler = ngx_event_accept; if (ngx_use_accept_mutex) { continue; } if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { if (ngx_add_conn(c) == NGX_ERROR) { return NGX_ERROR; } } else { /* 将监听对象连接的读事件添加到事件驱动模块中 */ if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #endif } return NGX_OK; }
参考资料:
《深入理解 Nginx 》
《nginx事件模块分析(二)》
以上就介绍了Nginx 事件模块,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。