1.配置文件
event事件模块,配置分为两层:ngx_events_module 事件模块 和 ngx_event_core_module 事件核心模块。
- ngx_events_module:模块类型NGX_CORE_MODULE,所以此模块在最外层核心模块解析“events”命令的时候会回调ngx_events_block函数。
- ngx_event_core_module:模块类型NGX_EVENT_MODULE,所以此模块在ngx_events_block函数被回调后,才能解析配置信息
最外层的events模块,类型NGX_CORE_MODULE,属于核心模块,核心模块在最开始配置文件初始化的时候,就会调用指令的命令集。所以在核心模块启动的时候就会调用events的模块配置解析指令函数:ngx_events_block
3. Event模块的初始化
ngx_event_module_init 模块初始化函数
ngx_event_module_init方法为事件核心模块的初始化函数。
// 在ngx_init_cycle里调用,fork子进程之前
// 创建共享内存,存放负载均衡锁和统计用的原子变量
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;
// events模块的配置结构体
// 实际上是一个存储void*指针的数组
cf = ngx_get_conf(cycle->conf_ctx, ngx_events_module);
// event_core模块的配置结构体
// 从数组cf里按序号查找
ecf = (*cf)[ngx_event_core_module.ctx_index];
// 上面的两行代码相当于:
// ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module)
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);
}
// core模块的配置结构体
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
// 获取核心配置的时间精度,用在epoll里更新缓存时间
ngx_timer_resolution = ccf->timer_resolution;
// unix专用代码, 可打开的最多文件描述符
#if !(NGX_WIN32)
{
ngx_int_t limit;
struct rlimit rlmt;
// 系统调用getrlimit,Linux内核对进程的限制
// RLIMIT_NOFILE,进程可打开的最大文件描述符数量,超出将产生EMFILE错误
if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
// 系统调用失败则记录alert级别日志
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"getrlimit(RLIMIT_NOFILE) failed, ignored");
} else {
// 成功获取内核参数
//
// rlmt.rlim_cur是系统的软限制
// event里配置的连接数不能超过系统内核限制
// 或者是配置的rlimit_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就是上限
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) */
// 如果非master/worker进程,即只启动一个进程,那么就没必要使用负载均衡锁
if (ccf->master == 0) {
return NGX_OK;
}
// 已经有了负载均衡锁,已经初始化过了,就没必要再做操作
if (ngx_accept_mutex_ptr) {
return NGX_OK;
}
/* cl should be equal to or greater than cache line size */
// cl是一个基本长度,可以容纳原子变量
// 对齐到cache line,操作更快
cl = 128;
// 最基本的三个:负载均衡锁,连接计数器,
size = cl /* ngx_accept_mutex */
+ cl /* ngx_connection_counter */
+ cl; /* ngx_temp_number */
// 其他统计用的原子变量
#if (NGX_STAT_STUB)
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
// 创建共享内存,存放负载均衡锁和统计用的原子变量
// 因为内存很小,而且仅用做统计,比较简单
// 所以不用slab管理
shm.size = size;
ngx_str_set(&shm.name, "nginx_shared_zone");
shm.log = cycle->log;
// 分配一块共享内存
if (ngx_shm_alloc(&shm) != NGX_OK) {
return NGX_ERROR;
}
// shared是共享内存的地址指针
shared = shm.addr;
// 第一个就是负载均衡锁
ngx_accept_mutex_ptr = (ngx_atomic_t *) shared;
// spin是-1则不使用信号量
// 只会自旋,不会导致进程睡眠等待
// 这样避免抢accept锁时的性能降低
ngx_accept_mutex.spin = (ngx_uint_t) -1;
// 初始化互斥锁
// spin是-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);
// 计数器置1
(void) ngx_atomic_cmp_set(ngx_connection_counter, 0, 1);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"counter: %p, %uA",
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;
}
4. ngx_conf_parse 解析顶层“event”的配置
ngx_init_cycle方法中会调用ngx_conf_parse方法,并且解析的/usr/local/nginx/conf/nginx.conf配置文件。此次调用只解析最顶层的配置信息“events”,而不会解析{}块中的内容
ngx_events_block 解析events块block中的内容
ngx_events_block方法为ngx_events_commands命令集的回调函数。在最顶层解析nginx.conf文件的时候,会进行核心模块的命令集遍历。
ngx_events_block中主要创建ngx_event_core_module事件的核心模块以及配置信息。
// 解析events配置块
// 设置事件模块的ctx_index
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;
// 不允许出现两个events配置块
// conf实际上是个二维数组,所以是void**
if (*(void **) conf) {
return "is duplicate";
}
/* count the number of the event modules and set up their indices */
// 得到所有的事件模块数量
// 设置事件模块的ctx_index
ngx_event_max_module = ngx_count_modules(cf->cycle, NGX_EVENT_MODULE);
// ctx是void***,也就是void** *,即指向二维数组的指针
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;
}
// 在cycle里存储这个指针
*(void **) conf = ctx;
// 对每一个事件模块调用create_conf创建配置结构体
// 事件模块的层次很简单,没有多级,所以二维数组就够了
for (i = 0; cf->cycle->modules[i]; i++) {
if (cf->cycle->modules[i]->type != NGX_EVENT_MODULE) {
continue;
}
m = cf->cycle->modules[i]->ctx;
// 调用create_conf创建配置结构体
if (m->create_conf) {
(*ctx)[cf->cycle->modules[i]->ctx_index] =
m->create_conf(cf->cycle);
if ((*ctx)[cf->cycle->modules[i]->ctx_index] == NULL) {
return NGX_CONF_ERROR;
}
}
}
// 暂存当前的解析上下文
pcf = *cf;
// 设置事件模块的新解析上下文
cf->ctx = ctx;
cf->module_type = NGX_EVENT_MODULE;
cf->cmd_type = NGX_EVENT_CONF;
// 递归解析事件相关模块
rv = ngx_conf_parse(cf, NULL);
// 恢复之前保存的解析上下文
*cf = pcf;
if (rv != NGX_CONF_OK) {
return rv;
}
// 解析完毕,需要初始化配置,即给默认值
for (i = 0; cf->cycle->modules[i]; i++) {
if (cf->cycle->modules[i]->type != NGX_EVENT_MODULE) {
continue;
}
m = cf->cycle->modules[i]->ctx;
if (m->init_conf) {
rv = m->init_conf(cf->cycle,
(*ctx)[cf->cycle->modules[i]->ctx_index]);
if (rv != NGX_CONF_OK) {
return rv;
}
}
}
return NGX_CONF_OK;
}
5. ngx_event_core_create_conf和ngx_event_core_init_conf
- ngx_event_core_create_conf:主要是创建event事件核心模块
- ngx_event_core_init_conf:初始化event事件核心模块
// 创建event_core模块的配置结构体,成员初始化为unset
static void *
ngx_event_core_create_conf(ngx_cycle_t *cycle)
{
ngx_event_conf_t *ecf;
ecf = ngx_palloc(cycle->pool, sizeof(ngx_event_conf_t));
if (ecf == NULL) {
return NULL;
}
ecf->connections = NGX_CONF_UNSET_UINT;
ecf->use = NGX_CONF_UNSET_UINT;
ecf->multi_accept = NGX_CONF_UNSET;
ecf->accept_mutex = NGX_CONF_UNSET;
ecf->accept_mutex_delay = NGX_CONF_UNSET_MSEC;
ecf->name = (void *) NGX_CONF_UNSET;
#if (NGX_DEBUG)
if (ngx_array_init(&ecf->debug_connection, cycle->pool, 4,
sizeof(ngx_cidr_t)) == NGX_ERROR)
{
return NULL;
}
#endif
return ecf;
}
// 所有模块配置解析完毕后,对配置进行初始化
// 如果有的指令没有写,就要给正确的默认值
// 模块默认使用epoll
// 默认不接受多个请求,也就是一次只accept一个连接
// 1.11.3之前默认使用负载均衡锁,之后默认关闭
static char *
ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf)
{
ngx_event_conf_t *ecf = conf;
#if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL)
int fd;
#endif
// rtsig在nginx 1.9.x已经删除
ngx_int_t i;
ngx_module_t *module;
ngx_event_module_t *event_module;
module = NULL;
// 测试epoll是否可用
#if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL)
fd = epoll_create(100);
// epoll调用可用,那么模块默认使用epoll
if (fd != -1) {
(void) close(fd);
// epoll调用可用,那么模块默认使用epoll
module = &ngx_epoll_module;
} else if (ngx_errno != NGX_ENOSYS) {
// epoll调用可用,那么模块默认使用epoll
module = &ngx_epoll_module;
}
#endif
// rtsig在nginx 1.9.x已经删除
#if (NGX_HAVE_DEVPOLL) && !(NGX_TEST_BUILD_DEVPOLL)
module = &ngx_devpoll_module;
#endif
#if (NGX_HAVE_KQUEUE)
module = &ngx_kqueue_module;
#endif
// 如果epoll不可用,那么默认使用select
#if (NGX_HAVE_SELECT)
if (module == NULL) {
module = &ngx_select_module;
}
#endif
// 还没有决定默认的事件模型
if (module == NULL) {
// 遍历所有的事件模块
for (i = 0; cycle->modules[i]; i++) {
if (cycle->modules[i]->type != NGX_EVENT_MODULE) {
continue;
}
event_module = cycle->modules[i]->ctx;
// 跳过event_core模块
if (ngx_strcmp(event_module->name->data, event_core_name.data) == 0)
{
continue;
}
// 使用数组里的第一个事件模块
module = cycle->modules[i];
break;
}
}
// 最后还没有决定默认的事件模型,出错
if (module == NULL) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "no events module found");
return NGX_CONF_ERROR;
}
// nginx每个进程可使用的连接数量,即cycle里的连接池大小
ngx_conf_init_uint_value(ecf->connections, DEFAULT_CONNECTIONS);
// 如果没有使用worker_connections指令,在这里设置
cycle->connection_n = ecf->connections;
// 决定使用的事件模型,之前的module只作为默认值,如果已经使用了use则无效
ngx_conf_init_uint_value(ecf->use, module->ctx_index);
// 初始化使用的事件模块的名字
event_module = module->ctx;
ngx_conf_init_ptr_value(ecf->name, event_module->name->data);
// 默认不接受多个请求,也就是一次只accept一个连接
ngx_conf_init_value(ecf->multi_accept, 0);
// 1.11.3之前默认使用负载均衡锁,之后默认关闭
ngx_conf_init_value(ecf->accept_mutex, 0);
// 默认负载均衡锁的等待时间是500毫秒
ngx_conf_init_msec_value(ecf->accept_mutex_delay, 500);
return NGX_CONF_OK;
}
参考资料: