【Nginx】启动过程
从应用程序的启动过程中main功能开始跟踪。
- 调用每个核心模块的create_conf方法创建存储配置项參数的结构体。
注意,非核心模块存储配置项的结构体不在这里创建,而是由核心模块负责创建。
- 调用配置模块提供的解析方法,遍历配置文件。对于每个配置项又遍历全部核心模块,核心模块感兴趣的配置项是存放在ngx_command_t结构体中的。找出对该配置项感兴趣的合兴模块后调用ngx_command_t中定义的解析方法。
- 调用全部核心模块的init_conf方法,依据解析的配置项參数进行初始化。
- 创建并打开所需的文件夹和文件。
- 初始化用于进程间通信的共享内存。
- 调用ngx_open_listening_sockets函数打开由各Nginx模块从配置文件里读取到的监听port。
全部的监听port都保存在ngx_cycle_t->listening数组中。存储元素是ngx_listening_t结构体。表示监听port及相关參数。
- 调用全部模块的init_module方法,这种方法保存在ngx_module_t->init_module函数指针中。
- ngx_terminate:表示强制关闭进程。由信号处理函数ngx_signal_handler函数置1.
- ngx_quit:表示优雅关闭进程,由信号处理函数ngx_signal_handler函数置1.
- ngx_reopen:表示又一次打开文件,由信号处理函数ngx_signal_handler函数置1.
- ngx_exiting:表示将要退出进程,仅在为0且ngx_quit被置的情况下置1.
static void
ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
{
ngx_int_t worker = (intptr_t) data;
ngx_uint_t i;
ngx_connection_t *c;
/* 该函数内会调用全部模块的init_process方法 */
ngx_worker_process_init(cycle, worker);
...
for ( ;; )
{
/* 退出进程标识 */
if (ngx_exiting)
{
c = cycle->connections;
/* 关闭全部连接 */
for (i = 0; i < cycle->connection_n; i++)
{
if (c[i].fd != -1 && c[i].idle)
{
c[i].close = 1; /* close标识置1 */
c[i].read->handler(c[i].read); /* 调用读事件处理方法 */
}
}
if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel)
{
/* 红黑树为空,已经处理全然部事件。调用全部模块的exit_process方法 */
ngx_worker_process_exit(cycle);
}
}
/* 还有事件须要处理,继续向下运行 */
ngx_process_events_and_timers(cycle); /* 处理事件,事件模块核心方法 */
/* 强制关闭进程 */
if (ngx_terminate)
ngx_worker_process_exit(cycle); /* 直接调用全部模块的exit_process方法退出worker进程 */
/* 优雅的关闭连接 */
if (ngx_quit)
{
ngx_quit = 0;
ngx_setproctitle("worker process is shutting down"); /* 改动进程名字 */
if (!ngx_exiting)
{
ngx_close_listening_sockets(cycle); /* 关闭监听句柄 */
ngx_exiting = 1; /* ngx_exiting标识唯一被改动的地方 */
}
}
if (ngx_reopen)
{
/* 又一次打开全部文件 */
ngx_reopen = 0;
ngx_reopen_files(cycle, -1);
}
}
}
和worker进程类似。master通过监控七个标志位来决定程序运行流。这七个标志位例如以下所看到的:
void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
...
/* 依据配置文件启动worker_processes个work子进程 */
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_RESPAWN);
/* master进程 */
for ( ;; )
{
sigsuspend(&set); /* 堵塞,等待信号 */
if (ngx_reap)
{
ngx_reap = 0;
/* 监控全部子进程,又一次启动非正常退出的子进程 */
live = ngx_reap_children(cycle);
}
/* live为0表示全部子进程已经退出 */
if (!live && (ngx_terminate || ngx_quit))
{
/* 满足上述条件,退出master进程,包含:
* 1、删除存储进程的pid文件
* 2、调用全部模块的exit_master方法
* 3、关闭监听port
* 4、销毁内存池
*/
ngx_master_process_exit(cycle);
}
if (ngx_terminate) /* 强制关闭 */
{
if (delay > 1000)
{
ngx_signal_worker_processes(cycle, SIGKILL); /* SIGKILL = 9 */
}
else
{
/* NGX_TERMINATE_SIGNAL = TERM = 15
* 向每一个子进程发送TERM信号
*/
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_TERMINATE_SIGNAL));
}
continue; /* 跳上去挂起 */
}
if (ngx_quit) /* 优雅的退出。向全部子进程发送QUIT信号 */
{
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); /* NGX_SHUTDOWN_SIGNAL = QUIT */
ls = cycle->listening.elts;
/* 关闭全部port */
for (n = 0; n < cycle->listening.nelts; n++)
ngx_close_socket(ls[n].fd);
cycle->listening.nelts = 0;
continue; /* 跳上去挂起 */
}
if (ngx_reconfigure) /* 须要又一次读取配置文件 */
{
/* 又一次读取配置文件后,生成新的worker进程,销毁旧的worker进程 */
ngx_reconfigure = 0;
cycle = ngx_init_cycle(cycle); /* 又一次配置ngx_cycle_t结构体 */
ngx_cycle = cycle;
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
/* 又一次派生子进程 */
ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN);
ngx_start_cache_manager_processes(cycle, 1);
live = 1; /* 表示有子进程在执行 */
/* 向旧的子进程发送QUIT信号,要求它们退出 */
ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
}
if (ngx_restart) /* 重新启动work进程 */
{
ngx_restart = 0;
ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN);
ngx_start_cache_manager_processes(cycle, 0);
live = 1; /* 表示有子进程在执行 */
}
if (ngx_reopen) /* 又一次打开全部文件 */
{
ngx_reopen = 0;
ngx_reopen_files(cycle, ccf->user);
/* 向全部子进程发送USR1信号,要求每一个子进程又一次打开文件 */
ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_REOPEN_SIGNAL));
}
if (ngx_change_binary) /* 平滑升级 */
{
ngx_change_binary = 0;
ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv); /* 新的子进程启动新版本号的Nginx */
}
if (ngx_noaccept) /* 优雅的关闭服务 */
{
ngx_noaccept = 0;
ngx_noaccepting = 1;
/* 向全部子进程发送QUIT信号,要求它们优雅的关闭服务 */
ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
}
}
}
版权声明:本文博主原创文章,博客,未经同意不得转载。
【Nginx】启动过程的更多相关文章
- Nginx学习之十一-Nginx启动框架处理流程
Nginx启动过程流程图 下面首先给出Nginx启动过程的流程图: ngx_cycle_t结构体 Nginx的启动初始化在src/core/nginx.c的main函数中完成,当然main函数是整个N ...
- 菜鸟nginx源码剖析 框架篇(一) 从main函数看nginx启动流程(转)
俗话说的好,牵牛要牵牛鼻子 驾车顶牛,处理复杂的东西,只要抓住重点,才能理清脉络,不至于深陷其中,不能自拔.对复杂的nginx而言,main函数就是“牛之鼻”,只要能理清main函数,就一定能理解其中 ...
- 【nginx】【转】Nginx启动框架处理流程
Nginx启动过程流程图: ngx_cycle_t结构体: Nginx的启动初始化在src/core/nginx.c的main函数中完成,当然main函数是整个Nginx的入口,除了完成启动初始化任务 ...
- 菜鸟nginx源代码剖析 框架篇(一) 从main函数看nginx启动流程
菜鸟nginx源代码剖析 框架篇(一) 从main函数看nginx启动流程 Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.c ...
- Nginx学习笔记(六) 源码分析&启动过程
Nginx的启动过程 主要介绍Nginx的启动过程,可以在/core/nginx.c中找到Nginx的主函数main(),那么就从这里开始分析Nginx的启动过程. 涉及到的基本函数 源码: /* * ...
- Nginx的启动过程
主要介绍Nginx的启动过程,可以在/core/nginx.c中找到Nginx的主函数main(),那么就从这里开始分析Nginx的启动过程. 涉及到的基本函数 源码: View Code Ngin ...
- nginx启动过程分析
nginx的启动过程紧紧环绕着ngx_cycle_t的结构体展开,首先通过ngx_get_options()获取命令行參数.然后通过ngx_time_init()进行时间的初始化.如全局变量ngx_c ...
- Nginx学习——Nginx启动、停止、重启和信号控制以及平滑升级
1.Nginx 启动与停止 (1)启动方式 启动格式:Nginx可执行文件地址 -c Nginx配置文件地址 /etc/local/nginx/sbin/nginx -c /root/dufy/ngi ...
- linux环境手动编译安装Nginx实践过程 附异常解决
1.下载nginx源码包并解压 可在http://nginx.org/en/download.html下载.tar.gz的源码包,如(nginx-1.4.7.tar.gz) 或者使用云盘下载 ht ...
随机推荐
- php调用dll
http://download.csdn.net/detail/pinghe2005/5108556
- 施用 maven shade plugin 解决 jar 或类的多版本冲突
施用 maven shade plugin 解决 jar 或类的多版本冲突 使用 maven shade plugin 解决 jar 或类的多版本冲突java 应用经常会碰到的依赖的三方库出现版本 ...
- Windows phone 8 学习笔记
Windows phone 8 学习笔记(1) 触控输入 http://www.apkbus.com/android-138547-1-1.html Windows phone 8 学习笔记(2) ...
- PrimusUI
小身材大用途,用PrimusUI驾驭你的页面 “PrimusUI”是自己在借鉴了如今网上很多开源的UI库,再经过自己整理加工的一个简单代码集合. 每个功能块的CSS代码都很少,力求简单易懂,低门槛,代 ...
- 【Java数据结构】Java数据结构之链表反转
我们都知道用C可以很简单的实现单链表反转,今天来学习下,在Java中如何实现链表反转. 思路很简单,定义一个类,这个类分成2块,一块是表示自身的标志,另外一个存储指向下一个元素的引用.通过互换相邻两个 ...
- Windows消息队列
一 Windows中有一个系统消息队列,对于每一个正在执行的Windows应用程序,系统为其建立一个“消息队列”,即应用程序队列,用来存放该程序可能 创建的各种窗口的消息.应用程序中含有一段称作“消息 ...
- Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上)
原文:[置顶] Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上) 我们在用手机的时候可能会发现,即使应用被放到后台再返回到前台数据依然保留(比如说我们正在玩游戏,突然电话 ...
- SINGLETON(单例模式)---(孤独的人)
很多时候,我们都很彷徨,因为,在身边的朋友,很少. package patterns.createable.singleton; /** * 孤独的人啊 * 我为你写了一个类 * 这个类,在我们的程序 ...
- Git权威指南学习笔记(二)Git暂存区
例如以下图所看到的: 左側为工作区,是我们的工作文件夹. 右側为版本号库,当中: index标记的是暂存区(stage),所处文件夹为.git/index,记录了文件的状态和变更信息. master标 ...
- python基础教程_学习笔记1:序列-1
序列 数据结构:通过某种方式组织在一起的数据元素的集合,这些数据元素能够是数字或者字符,甚至能够是其它数据结构. python中,最主要的数据结构是序列. 序列中的每一个元素被分配一个序号--即元素的 ...