首页 > 代码库 > Nginx 启动初始化过程
Nginx 启动初始化过程
Nginx 启动过程
Nginx 的启动初始化由 main 函数完成,该函数是整个 Nginx 的入口,该函数完成 Nginx 启动初始化任务,也是所有功能模块的入口。Nginx 的初始化工作主要是一个类型为 ngx_cycle_t 类型的全局变量。main 函数定义在文件:src/?core/?nginx.c
Nginx 启动过程如下。
- 调用 ngx_get_options() 解析命令参数;
- 显示版本号与帮助信息;
- 调用 ngx_time_init() 初始化并更新时间;
- 调用 ngx_log_init() 初始化日志;
- 创建全局变量 init_cycle 的内存池 pool;
- 调用 ngx_save_argv() 保存命令行参数至全局变量ngx_os_argv、ngx_argc、ngx_argv 中;
- 调用 ngx_process_options() 初始化 init_cycle 的 prefix, conf_prefix, conf_file, conf_param 等字段;
- 调用 ngx_os_init() 初始化系统相关变量;
- 调用 ngx_crc32_table_init() 初始化CRC表;
- 调用 ngx_add_inherited_sockets() 继承 sockets;
- 通过环境变量 NGINX 完成 socket 的继承,将其保存在全局变量 init_cycle 的 listening 数组中;
- 初始化每个模块 module 的index,并计算 ngx_max_module;
- 调用 ngx_init_cycle() 进行初始化全局变量 init_cycle,这个步骤非常重要;
- 调用 ngx_signal_process() 处理进程信号;
- 调用 ngx_init_signals() 注册相关信号;
- 若无继承 sockets,则调用 ngx_daemon() 创建守护进程,并设置其标志;
- 调用 ngx_create_pidfile() 创建进程 ID 记录文件;
- 进入进程处理:
- 单进程工作模式;
- 多进程工作模式,即 master-worker 多进程工作模式;
int ngx_cdecl main(int argc, char *const *argv) { ngx_int_t i; ngx_log_t *log; ngx_cycle_t *cycle, init_cycle; ngx_core_conf_t *ccf; ngx_debug_init(); if (ngx_strerror_init() != NGX_OK) { return 1; } /* 解析命令行参数 */ if (ngx_get_options(argc, argv) != NGX_OK) { return 1; } /* 显示版本号与帮助信息 */ if (ngx_show_version) { ngx_write_stderr("nginx version: " NGINX_VER NGX_LINEFEED); if (ngx_show_help) { ngx_write_stderr( "Usage: nginx [-?hvVtq] [-s signal] [-c filename] " "[-p prefix] [-g directives]" NGX_LINEFEED NGX_LINEFEED "Options:" NGX_LINEFEED " -?,-h : this help" NGX_LINEFEED " -v : show version and exit" NGX_LINEFEED " -V : show version and configure options then exit" NGX_LINEFEED " -t : test configuration and exit" NGX_LINEFEED " -q : suppress non-error messages " "during configuration testing" NGX_LINEFEED " -s signal : send signal to a master process: " "stop, quit, reopen, reload" NGX_LINEFEED #ifdef NGX_PREFIX " -p prefix : set prefix path (default: " NGX_PREFIX ")" NGX_LINEFEED #else " -p prefix : set prefix path (default: NONE)" NGX_LINEFEED #endif " -c filename : set configuration file (default: " NGX_CONF_PATH ")" NGX_LINEFEED " -g directives : set global directives out of configuration " "file" NGX_LINEFEED NGX_LINEFEED ); } if (ngx_show_configure) { ngx_write_stderr( #ifdef NGX_COMPILER "built by " NGX_COMPILER NGX_LINEFEED #endif #if (NGX_SSL) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME "TLS SNI support enabled" NGX_LINEFEED #else "TLS SNI support disabled" NGX_LINEFEED #endif #endif "configure arguments:" NGX_CONFIGURE NGX_LINEFEED); } if (!ngx_test_config) { return 0; } } /* TODO */ ngx_max_sockets = -1; /* 初始化并更新时间 */ ngx_time_init(); #if (NGX_PCRE) ngx_regex_init(); #endif ngx_pid = ngx_getpid(); /* 初始化日志信息 */ log = ngx_log_init(ngx_prefix); if (log == NULL) { return 1; } /* STUB */ #if (NGX_OPENSSL) ngx_ssl_init(log); #endif /* * init_cycle->log is required for signal handlers and * ngx_process_options() */ /* 全局变量init_cycle清零,并创建改变量的内存池pool */ ngx_memzero(&init_cycle, sizeof(ngx_cycle_t)); init_cycle.log = log; ngx_cycle = &init_cycle; init_cycle.pool = ngx_create_pool(1024, log); if (init_cycle.pool == NULL) { return 1; } /* 保存命令行参数至全局变量ngx_os_argv、ngx_argc、ngx_argv */ if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) { return 1; } /* 初始化全局变量init_cycle中的成员:prefix、conf_prefix、conf_file、conf_param 等字段 */ if (ngx_process_options(&init_cycle) != NGX_OK) { return 1; } /* 初始化系统相关变量,如:内存页面大小ngx_pagesize、最大连接数ngx_max_sockets等 */ if (ngx_os_init(log) != NGX_OK) { return 1; } /* * ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init() */ /* 初始化 CRC 表(循环冗余校验表) */ if (ngx_crc32_table_init() != NGX_OK) { return 1; } /* 通过环境变量NGINX完成socket的继承,将其保存在全局变量init_cycle的listening数组中 */ if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) { return 1; } /* 初始化每个模块module的index,并计算ngx_max_module */ ngx_max_module = 0; for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]->index = ngx_max_module++; } /* 初始化全局变量init_cycle ,这里很重要 */ cycle = ngx_init_cycle(&init_cycle); if (cycle == NULL) { if (ngx_test_config) { ngx_log_stderr(0, "configuration file %s test failed", init_cycle.conf_file.data); } return 1; } if (ngx_test_config) { if (!ngx_quiet_mode) { ngx_log_stderr(0, "configuration file %s test is successful", cycle->conf_file.data); } return 0; } /* 信号处理 */ if (ngx_signal) { return ngx_signal_process(cycle, ngx_signal); } ngx_os_status(cycle->log); ngx_cycle = cycle; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) { ngx_process = NGX_PROCESS_MASTER; } #if !(NGX_WIN32) /* 初始化信号,注册相关信号 */ if (ngx_init_signals(cycle->log) != NGX_OK) { return 1; } /* 若无socket继承,则创建守护进程,并设置守护进程标志 */ if (!ngx_inherited && ccf->daemon) { if (ngx_daemon(cycle->log) != NGX_OK) { return 1; } ngx_daemonized = 1; } if (ngx_inherited) { ngx_daemonized = 1; } #endif /* 记录进程ID */ if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { return 1; } if (ngx_log_redirect_stderr(cycle) != NGX_OK) { return 1; } if (log->file->fd != ngx_stderr) { if (ngx_close_file(log->file->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_close_file_n " built-in log failed"); } } ngx_use_stderr = 0; /* 进入进程处理 */ if (ngx_process == NGX_PROCESS_SINGLE) { /* 单进程工作模式 */ ngx_single_process_cycle(cycle); } else { /* master-worker 多进程模式工作 */ ngx_master_process_cycle(cycle); } return 0; }
ngx_cycle_t 变量初始化
ngx_cycle_t 结构体初始化
在初始化过程中,ngx_cycle_t 类型的全局变量最为重要,该类型结构定义如下:src/?core/?ngx_cycle.h
/* ngx_cycle_t 全局变量数据结构 */ struct ngx_cycle_s { /* * 保存所有模块配置项的结构体指针,该数组每个成员又是一个指针, * 这个指针又指向存储指针的数组 */ void ****conf_ctx; /* 所有模块配置上下文的数组 */ ngx_pool_t *pool; /* 内存池 */ ngx_log_t *log; /* 日志 */ ngx_log_t new_log; ngx_uint_t log_use_stderr; /* unsigned log_use_stderr:1; */ ngx_connection_t **files; /* 连接文件 */ ngx_connection_t *free_connections; /* 空闲连接 */ ngx_uint_t free_connection_n;/* 空闲连接的个数 */ /* 可再利用的连接队列 */ ngx_queue_t reusable_connections_queue; ngx_array_t listening; /* 监听数组 */ ngx_array_t paths; /* 路径数组 */ ngx_list_t open_files; /* 已打开文件的链表 */ ngx_list_t shared_memory;/* 共享内存链表 */ ngx_uint_t connection_n; /* 已连接个数 */ ngx_uint_t files_n; /* 已打开文件的个数 */ ngx_connection_t *connections; /* 连接 */ ngx_event_t *read_events; /* 读事件 */ ngx_event_t *write_events; /* 写事件 */ /* old 的 ngx_cycle_t 对象,用于引用前一个 ngx_cycle_t 对象的成员 */ ngx_cycle_t *old_cycle; ngx_str_t conf_file; /* nginx 配置文件 */ ngx_str_t conf_param; /* nginx 处理配置文件时需要特殊处理的,在命令行携带的参数 */ ngx_str_t conf_prefix; /* nginx 配置文件的路径 */ ngx_str_t prefix; /* nginx 安装路径 */ ngx_str_t lock_file; /* 加锁文件 */ ngx_str_t hostname; /* 主机名 */ };
ngx_init_cycle() 初始化函数
该结构的初始化是通过函数 ngx_init_cycle() 完成的,该函数定义如下:src/?core/?ngx_cycle.c
ngx_cycle_t 结构全局变量初始化过程如下:
- 更新时区与时间;
- 创建内存池;
- 分配 ngx_cycle_t 结构体内存,创建该结构的变量 cycle 并初始化;
- 遍历所有 core模块,并调用该模块的 create_conf() 函数;
- 配置文件解析;
- 遍历所有core模块,并调用core模块的init_conf()函数;
- 遍历 open_files 链表中的每一个文件并打开;
- 创建新的共享内存并初始化;
- 遍历 listening 数组并打开所有侦听;
- 提交新的 cycle 配置,并调用所有模块的init_module;
- 关闭或删除不被使用的在 old_cycle 中的资源:
- 释放多余的共享内存;
- 关闭多余的侦听 sockets;
- 关闭多余的打开文件;
ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle) { void *rv; char **senv, **env; ngx_uint_t i, n; ngx_log_t *log; ngx_time_t *tp; ngx_conf_t conf; ngx_pool_t *pool; ngx_cycle_t *cycle, **old; ngx_shm_zone_t *shm_zone, *oshm_zone; ngx_list_part_t *part, *opart; ngx_open_file_t *file; ngx_listening_t *ls, *nls; ngx_core_conf_t *ccf, *old_ccf; ngx_core_module_t *module; char hostname[NGX_MAXHOSTNAMELEN]; /* 更新时区 */ ngx_timezone_update(); /* force localtime update with a new timezone */ tp = ngx_timeofday(); tp->sec = 0; /* 更新时间 */ ngx_time_update(); /* 创建内存池pool,并初始化 */ log = old_cycle->log; pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); if (pool == NULL) { return NULL; } pool->log = log; /* 创建ngx_cycle_t 结构体变量 */ cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t)); if (cycle == NULL) { ngx_destroy_pool(pool); return NULL; } /* 初始化ngx_cycle_t 结构体变量 cycle */ cycle->pool = pool; cycle->log = log; cycle->old_cycle = old_cycle; cycle->conf_prefix.len = old_cycle->conf_prefix.len; cycle->conf_prefix.data = http://www.mamicode.com/ngx_pstrdup(pool, &old_cycle->conf_prefix);>
参考资料:《 nginx源码分析—启动流程》
《Nginx启动初始化过程》
Nginx 启动初始化过程
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。