news 2026/6/14 19:45:59

ngx_master_process_cycle

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ngx_master_process_cycle

1 定义

ngx_master_process_cycle 函数 定义在 ./nginx-1.24.0/src/os/unix/ngx_process_cycle.c

2 作用

ngx_master_process_cycle 是 Nginx 主进程的核心循环函数。 它负责: 设置信号处理掩码、 启动 worker 和缓存管理进程, 然后进入无限循环, 通过 `sigsuspend` 等待信号, 并根据全局标志位处理 子进程回收、服务停止、配置热重载、日志滚动等管理任务。
核心任务包括: 1 管理子进程: 启动、监控和重启 worker 进程 2 信号处理: 阻塞并响应各种信号,执行相应操作。 3 进程生命周期控制: 根据信号或子进程状态,执行配置重新加载、优雅停机或强制终止, 并在子进程异常退出时重新生成。 4 保持 master 持续运行: 循环处理直到所有子进程退出且收到退出信号为止。

3 详解

1 函数签名

voidngx_master_process_cycle(ngx_cycle_t*cycle)
返回值 返回类型:void 函数不返回任何值。 一旦进入该函数,主进程将陷入无限循环,直到收到终止信号退出整个进程, 因此从调用者的角度看,这个函数永远不会正常返回
函数名 ngx_master_process_cycle 命名空间前缀 ngx_: Nginx 函数的标准前缀 master_process: 明确指出该函数仅在 master 进程(主进程)中运行。 Nginx 在启动时根据配置和进程模式, 会调用 ngx_master_process_cycle 或 ngx_single_process_cycle 分支。 cycle(周期): cycle 表明其本质是 阻塞式控制主循环,而非一次性初始化函数。 cycle 强调了这个函数将在给定的运行周期中不断循环处理管理事件。 整体语义: 函数名准确传达了它的角色—— 在 master 进程的运行上下文中进入无限事件循环。 Master 进程的大脑。 不负责网络 I/O, 专职进程调度、信号路由、配置热重载、平滑升级与优雅退出管控。 是 Nginx 高可用架构的调度中枢。
参数 ngx_cycle_t *cycle 类型: 指向 ngx_cycle_t 结构体的指针, 这是 Nginx 全局运行环境的根对象, 包含了所有核心数据:配置树、模块上下文、连接池、监听 socket、日志对象、时间缓存等等。 在函数中的角色: 作为 master 进程的运行时上下文: 函数内部几乎所有操作都离不开 cycle。 唯一参数,承载一切: Nginx 的设计哲学中,cycle 是各个模块和进程访问全局资源的入口。 因此 ngx_master_process_cycle 只需要一个 cycle 指针,就可以获取所有必要的信息。 设计意义: 将整个运行环境作为参数传递,而非依赖分散的全局变量,使得代码更模块化 支持配置热重载: 重载时会用新的 cycle 替换旧的, 而旧的 cycle 会在所有引用释放后被安全销毁, 主循环只需要更新局部变量 cycle 即可。
总结 ngx_master_process_cycle 的函数签名: void 返回值表示函数将进入永久循环,不会正常返回。 函数名清晰地表达了它的职责——在 master 进程的运行周期中进行循环管理。 唯一的 cycle 参数提供了主进程所需的全部运行时上下文,体现了 Nginx 高度集中的环境管理策略。 这个签名是 Nginx 进程管理模型的核心入口, 它将 main 函数的控制权转移给主进程的管理循环, 从此 Nginx 开始正式服务并响应各种管理信号。

2 逻辑流程

1 信号屏蔽 2 进程标题修改 3 启动 worker 进程 4 master 进程循环

{char*title;u_char*p;size_tsize;ngx_int_ti;ngx_uint_tsigio;sigset_tset;structitimervalitv;ngx_uint_tlive;ngx_msec_tdelay;ngx_core_conf_t*ccf;
局部变量声明

1 信号屏蔽

sigemptyset(&set);sigaddset(&set,SIGCHLD);sigaddset(&set,SIGALRM);sigaddset(&set,SIGIO);sigaddset(&set,SIGINT);sigaddset(&set,ngx_signal_value(NGX_RECONFIGURE_SIGNAL));sigaddset(&set,ngx_signal_value(NGX_REOPEN_SIGNAL));sigaddset(&set,ngx_signal_value(NGX_NOACCEPT_SIGNAL));sigaddset(&set,ngx_signal_value(NGX_TERMINATE_SIGNAL));sigaddset(&set,ngx_signal_value(NGX_SHUTDOWN_SIGNAL));sigaddset(&set,ngx_signal_value(NGX_CHANGEBIN_SIGNAL));if(sigprocmask(SIG_BLOCK,&set,NULL)==-1){ngx_log_error(NGX_LOG_ALERT,cycle->log,ngx_errno,"sigprocmask() failed");}sigemptyset(&set);
整体设计意义 避免异步中断: Master 进程的核心工作是管理子进程和处理配置变更, 这些操作必须原子化,不能在任意代码位置被信号打断。 阻塞信号使得信号处理被延迟到主循环中的安全点。 经典的同步模式: sigprocmask 阻塞信号 → 主循环检查标志 → sigsuspend(&empty_set) 挂起等待信号。 (检查标志与挂起之间信号可能到达) 集中管理: 所有管理信号都通过全局标志(如 ngx_reconfigure、ngx_reopen)驱动, 逻辑清晰且易于扩展。
#1 将信号集 set 清空,使其不包含任何信号。 必须先清空集合,才能开始添加需要的信号。避免残留的未定义位影响后续操作。
#2 将 4 个标准 POSIX 信号逐个加入集合 SIGCHLD: SIGALRM: SIGIO: SIGINT:
#3 通过 Nginx 封装的宏 ngx_signal_value(), 将 Nginx 内部统一信号编号 转换为系统实际的信号值 将逻辑信号名转换为实际操作系统信号编号,并加入集合。 实现跨平台信号抽象。不同 OS 的信号编号可能不同, 该宏在编译期自动映射,保证核心逻辑与平台解耦。 #3-1 NGX_RECONFIGURE_SIGNAL → SIGHUP 热重载配置 当 master 收到此信号时, 会重新读取配置文件、初始化新的 cycle、启动新的 worker 进程, 并通知旧 worker 优雅退出,实现热重载。 #3-2 NGX_REOPEN_SIGNAL → SIGUSR1 日志轮转 用户发送该信号后,master 会重新打开自己的日志文件, 并向所有 worker 进程发送同一信号,使它们也能重新打开日志文件 #3-3 NGX_NOACCEPT_SIGNAL → SIGWINCH 停止接受连接: 平滑升级或维护时,指示 Worker 停止 accept() 向旧 master 发送此信号,会让旧 worker 进程不再接受新连接, 待现有连接处理完毕后自动退出,从而实现无缝升级。 #3-4 NGX_TERMINATE_SIGNAL → SIGTERM 强制终止:带超时倒计时,超时未退出则发 SIGKILL 强杀 系统默认的终止信号。 Nginx 收到后,master 会立即向所有子进程发送 SIGTERM, 并等待一段延迟时间后若子进程仍未退出则发送 SIGKILL。用于快速停止服务 #3-5 NGX_SHUTDOWN_SIGNAL → SIGQUIT 优雅关闭:Worker 处理完当前请求后自行退出 master 收到 SIGQUIT 后,会向所有子进程发送 SIGQUIT,让它们优雅地完成当前请求后退出, 同时 master 关闭监听套接字并等待子进程全部结束,最后自身退出。用于无损停机。 #3-6 NGX_CHANGEBIN_SIGNAL → SIGUSR2 二进制平滑升级:Fork 出新 Master 进程,继承监听套接字实现零停机升级 当需要升级 Nginx 可执行文件时,向 master 发送 SIGUSR2。 master 会执行新版本的二进制程序(通过 ngx_exec_new_binary), 新进程启动后接管监听端口,旧 master 继续运行并管理旧 worker 进程,最终通过 SIGWINCH 完成切换。 这是 Nginx 热升级的核心机制。
#4 将前面构造的信号集设置为进程的信号掩码,阻塞这些信号,
sigprocmask(SIG_BLOCK, &set, NULL) 系统调用: sigprocmask 用于检查或更改当前进程的信号掩码(即被阻塞的信号集合)。 被阻塞的信号将不会被进程立即处理,而是处于挂起状态,直到解除阻塞。 第一个参数 SIG_BLOCK: 指定操作类型。 SIG_BLOCK 表示将第二个参数指向的信号集添加到当前信号掩码中(即阻塞这些信号)。 其他可能的值包括 SIG_SETMASK(直接设置掩码)和 SIG_UNBLOCK(解除阻塞)。 第二个参数 &set: 指向之前填充好的信号集。 即需要被阻塞的信号 第三个参数 NULL: 通常用于保存旧的信号掩码。 这里传入 NULL 表示不需要保存旧掩码,因为后续不会用到。 调用后,上述所有信号都被加入到 master 进程的阻塞集中。 此时如果这些信号被发送给 master 进程, 它们将不会立即触发信号处理函数,而是被内核挂起, 直到后续解除阻塞(通过 sigsuspend 或 sigprocmask(SIG_UNBLOCK))时才会递送。

#5 sigemptyset(&set); 清空 信号集合,以备后续使用

2 进程标题修改

size=sizeof(master_process);for(i=0;i<ngx_argc;i++){size+=ngx_strlen(ngx_argv[i])+1;}
计算存储进程标题所需的内存大小 总长度 = 固定前缀长度 + ∑(每个启动参数的长度 + 1个空格分隔符) 该结果将直接用于下一步 ngx_pnalloc() 的内存分配请求。

title=ngx_pnalloc(cycle->pool,size);if(title==NULL){/* fatal */exit(2);}
分配进程标题所需的内存

p=ngx_cpymem(title,master_process,sizeof(master_process)-1);for(i=0;i<ngx_argc;i++){*p++=' ';p=ngx_cpystrn(p,(u_char*)ngx_argv[i],size);}
将进程标题的基础字符串和所有命令行参数拼接到 title 缓冲区中

ngx_setproctitle(title);
将当前 master 进程在系统进程列表(如 ps 命令)中显示的标题, 修改为之前构造好的、包含详细启动参数的自定义字符串

3 启动 worker 进程

ccf=(ngx_core_conf_t*)ngx_get_conf(cycle->conf_ctx,ngx_core_module);ngx_start_worker_processes(cycle,ccf->worker_processes,NGX_PROCESS_RESPAWN);ngx_start_cache_manager_processes(cycle,0);
读取核心配置,并启动 worker 进程与缓存管理进程, 完成 master 进程对子进程的初始创建
#1 读取核心配置 获取 ngx_core_module 模块的配置 获取核心配置后,master 进程才能知道应该启动多少个 worker 进程, 以及后续操作中需要的其他核心参数。
#2 启动指定数量的 worker 子进程,并设置 master 对它们的监控策略 参数: cycle: 当前周期对象,传递给子进程使用。 ccf->worker_processes: worker 进程的数量(例如配置 worker_processes 4; 则值为 4)。 NGX_PROCESS_RESPAWN: 标志位,表示这些 worker 进程在异常退出时, master 应自动重新生成(respawn)新的进程来替代。
  • ngx_start_worker_processes
#3 启动缓存管理进程。 缓存管理进程不参与网络请求处理, 它们专门执行缓存文件的管理任务(例如过期缓存清理、缓存加载等)。 参数: cycle: 当前周期对象。 0: 第二个参数 0 表示“非重载启动” 在初次启动时,会根据配置创建缓存管理进程。 意义:将缓存管理工作从 worker 进程中剥离出来, 避免影响 worker 处理请求的性能; 同时集中管理缓存,提高效率。 如果没有配置任何缓存, 该函数不会创建任何进程,调用无害。

4 master 进程循环

ngx_new_binary=0;delay=0;sigio=0;live=1;
初始化 master 进程主循环的状态变量。 它们各自控制着 master 进程的终止流程、热升级状态以及子进程存活检测。
作用:将“正在执行二进制热升级”的标志置为假。 逻辑:这是一个全局变量,当 master 接收到 SIGUSR2(NGX_CHANGEBIN_SIGNAL) 并成功启动新版本的 master 进程后,会将其设为 1。 此处初始化为 0,表示当前未处于热升级流程中。
作用:将“终止延迟时间”清零。 逻辑:delay 用于在强制终止(ngx_terminate)时, 逐步升级信号的延迟策略。 当 master 需要立即停止所有 worker 进程时, 首先向它们发送 SIGTERM,并设置一个初始延迟(如 50ms)。 如果在延迟后仍有 worker 未退出,会再次发送信号,并将延迟翻倍, 最终可能发送 SIGKILL。 此处初始化为 0,表示尚未进入任何终止等待。
作用:将“终止信号发送计数器”清零。 逻辑:sigio 用于在 ngx_terminate 分支中控制信号的发送节奏。 它记录还需要等待多少个 SIGIO(或可理解为还需要进行几轮“信号发送 — 等待 — 再检查”)。 初始为 0,表示未处于任何需要计数等待的阶段。 当开始终止时,它会被设置为 worker_processes + 2, 然后每次 sigsuspend 返回后递减,直到降为 0 才再次发送信号, 从而实现了“等待所有 worker 响应后再发下一轮信号”的效果。
作用:将“是否有存活的子进程”标志设为真(1)。 逻辑:live 用于在每次 sigsuspend 后判断是否需要继续运行。 如果 live 变为 0 且同时 ngx_terminate 或 ngx_quit 为真, master 会调用 ngx_master_process_exit 退出。 此处初始化为 1,是因为刚刚启动了 worker 和 cache 进程,必定有子进程存活。 后续 ngx_reap_children 会根据实际收割情况更新 live(0 表示所有子进程均已退出)。 意义:正确反映了当前系统中的子进程状态,使得退出逻辑能够准确判断何时安全退出。
这些变量会在循环中被修改,控制 master 的行为。

master 进程的主循环,永不主动退出
for(;;){if(delay){if(ngx_sigalrm){sigio=0;delay*=2;ngx_sigalrm=0;}ngx_log_debug1(NGX_LOG_DEBUG_EVENT,cycle->log,0,"termination cycle: %M",delay);itv.it_interval.tv_sec=0;itv.it_interval.tv_usec=0;itv.it_value.tv_sec=delay/1000;itv.it_value.tv_usec=(delay%1000)*1000;if(setitimer(ITIMER_REAL,&itv,NULL)==-1){ngx_log_error(NGX_LOG_ALERT,cycle->log,ngx_errno,"setitimer() failed");}}ngx_log_debug0(NGX_LOG_DEBUG_EVENT,cycle->log,0,"sigsuspend");sigsuspend(&set);
sigsuspend(&set); 系统调用 参数是要阻塞的信号 传入空集表示临时解除所有信号的阻塞 挂起进程,直到收到任意信号 信号处理函数返回后,sigsuspend 将进程的信号掩码恢复为调用前的值

ngx_time_update();ngx_log_debug1(NGX_LOG_DEBUG_EVENT,cycle->log,0,"wake up, sigio %i",sigio);
更新 Nginx 内部缓存的各种时间值

if(ngx_reap){ngx_reap=0;ngx_log_debug0(NGX_LOG_DEBUG_EVENT,cycle->log,0,"reap children");live=ngx_reap_children(cycle);}
#1 ngx_reap: 全局标志变量,初始值为 0。 当 master 进程收到 SIGCHLD 信号时, 信号处理函数会将 ngx_reap 设置为 1。 在 Unix/Linux 系统编程中, SIGCHLD 信号的核心作用是: 当子进程的状态发生改变时, 内核通过该信号异步通知父进程。 检查是否有子进程状态发生变化(终止或暂停)。 如果 ngx_reap 为真,说明至少有一个子进程退出,需要执行回收操作。
#2 清除 ngx_reap 标志,避免重复处理同一个信号 (因为 SIGCHLD 可能会在短时间内多次触发,但一次回收可以处理所有已退出的子进程)。 确保每次 SIGCHLD 信号只触发一次回收逻辑
#3 输出调试日志,记录回收动作触发
#4 调用 ngx_reap_children 函数 遍历所有已注册的子进程 对每个已终止的子进程调用 waitpid 获取退出状态 返回值 live: 1 表示还有至少一个活跃的子进程(包括正在运行或重新生成的), 0 表示所有子进程都已退出且没有重新生成。 live 用于后续判断 master 进程是否可以退出

if(!live&&(ngx_terminate||ngx_quit)){ngx_master_process_exit(cycle);}
判断 master 进程是否可以安全退出 !live 为真表示 没有活跃的子进程 (ngx_terminate || ngx_quit) 要其中任一标志为真,即表示 master 已经收到了退出指令 调用 ngx_master_process_exit 函数 执行 master 进程的退出清理工作

if(ngx_terminate){if(delay==0){delay=50;}if(sigio){sigio--;continue;}sigio=ccf->worker_processes+2/* cache processes */;if(delay>1000){ngx_signal_worker_processes(cycle,SIGKILL);}else{ngx_signal_worker_processes(cycle,ngx_signal_value(NGX_TERMINATE_SIGNAL));}continue;}
全局标志 ngx_terminate 在信号处理函数中被设置为 1(收到 SIGTERM 或 SIGINT)。 一旦进入此分支,表示 master 需要强制终止整个 Nginx 服务。

if(ngx_quit){ngx_signal_worker_processes(cycle,ngx_signal_value(NGX_SHUTDOWN_SIGNAL));ngx_close_listening_sockets(cycle);continue;}
全局标志 ngx_quit 在 SIGQUIT 信号处理函数中被设置为 1 含义:用户要求 Nginx 优雅停止服务, 即处理完当前所有正在进行的请求后再退出,不中断现有连接
ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); 函数作用:向所有 worker 进程和 cache 管理进程发送指定的信号。 信号参数: NGX_SHUTDOWN_SIGNAL 通常映射为 SIGQUIT(与 master 收到的信号相同)。 子进程行为: Worker 进程收到 SIGQUIT 后,会设置自己的 ngx_quit 标志,进入优雅关闭流程: 关闭监听套接字(不再接受新连接)。 处理完当前正在处理的请求后,退出进程。 Cache 管理进程同样会收到 SIGQUIT,执行相应的清理后退出。 意义: 通知所有子进程开始优雅退出,但不强制立即终止,给它们时间完成已有工作。
ngx_close_listening_sockets(cycle); 函数作用:关闭 master 进程持有的所有监听套接字(例如 80、443 端口)。 Master 进程本身不处理连接, 但它持有监听套接字的文件描述符(在 cycle->listening 数组中)。
continue; 作用: 跳过当前循环迭代中后续的其他信号处理分支(例如 ngx_reconfigure、ngx_terminate 等), 直接回到循环开头。 为什么需要 continue? 因为已经进入优雅关闭流程, master 不应再响应其他信号(如重新配置、重新打开日志等), 否则可能干扰关闭过程。 回到循环开头后, 会重新进入 sigsuspend 等待信号(主要是 SIGCHLD,等待子进程退出) 后续当子进程逐个退出时,ngx_reap 分支会回收它们,并更新 live 变量。 当 live == 0 且 ngx_quit 仍为真时,master 会调用 ngx_master_process_exit 退出。

if(ngx_reconfigure){ngx_reconfigure=0;if(ngx_new_binary){ngx_start_worker_processes(cycle,ccf->worker_processes,NGX_PROCESS_RESPAWN);ngx_start_cache_manager_processes(cycle,0);ngx_noaccepting=0;continue;}ngx_log_error(NGX_LOG_NOTICE,cycle->log,0,"reconfiguring");cycle=ngx_init_cycle(cycle);if(cycle==NULL){cycle=(ngx_cycle_t*)ngx_cycle;continue;}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);/* allow new processes to start */ngx_msleep(100);live=1;ngx_signal_worker_processes(cycle,ngx_signal_value(NGX_SHUTDOWN_SIGNAL));}
处理配置重载

重启子进程
if(ngx_restart){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_log_error(NGX_LOG_NOTICE,cycle->log,0,"reopening logs");ngx_reopen_files(cycle,ccf->user);ngx_signal_worker_processes(cycle,ngx_signal_value(NGX_REOPEN_SIGNAL));}
重新打开所有日志文件

if(ngx_change_binary){ngx_change_binary=0;ngx_log_error(NGX_LOG_NOTICE,cycle->log,0,"changing binary");ngx_new_binary=ngx_exec_new_binary(cycle,ngx_argv);}
用户请求 Nginx 平滑升级到新版本的可执行文件。

if(ngx_noaccept){ngx_noaccept=0;ngx_noaccepting=1;ngx_signal_worker_processes(cycle,ngx_signal_value(NGX_SHUTDOWN_SIGNAL));}}}
不再接受新连接,通常用于平滑升级过程中让旧 worker 进程逐步退出。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 19:44:52

5分钟搭建Windows AirPlay接收器:免费开源方案全解析

5分钟搭建Windows AirPlay接收器&#xff1a;免费开源方案全解析 【免费下载链接】airplay2-win Airplay2 for windows 项目地址: https://gitcode.com/gh_mirrors/ai/airplay2-win 还在为苹果设备无法无线投屏到Windows电脑而烦恼吗&#xff1f;Airplay2-Win开源项目彻…

作者头像 李华
网站建设 2026/6/14 19:41:59

3分钟搞定:Yuzu模拟器终极安装指南,轻松玩转Switch游戏!

3分钟搞定&#xff1a;Yuzu模拟器终极安装指南&#xff0c;轻松玩转Switch游戏&#xff01; 【免费下载链接】yuzu-downloads 项目地址: https://gitcode.com/GitHub_Trending/yu/yuzu-downloads 你是否曾经梦想在电脑上畅玩任天堂Switch的经典游戏&#xff1f;现在&am…

作者头像 李华
网站建设 2026/6/14 19:37:11

Python的UnitTest接口自动化实战(六)

一.项目配置 1.目的1.1.处理不同的测试环境(开发环境、测试环境)1.2.不同的项目,不改写代码1.3.封装彻底,解耦合二.配置文件 1.ini、conf、cnf、cfg1.1.格式:section为段,配置文件中不需要引号,且key大小写不敏感 </

作者头像 李华
网站建设 2026/6/14 19:37:07

Cursor Free VIP破解工具:5分钟免费解锁AI编程助手完整教程

Cursor Free VIP破解工具&#xff1a;5分钟免费解锁AI编程助手完整教程 【免费下载链接】cursor-free-vip [Support 0.45]&#xff08;Multi Language 多语言&#xff09;自动注册 Cursor Ai &#xff0c;自动重置机器ID &#xff0c; 免费升级使用Pro 功能: Youve reached you…

作者头像 李华
网站建设 2026/6/14 19:31:56

MES系统实施有哪些难点?常见问题与解决方案详细说明

MES系统实施的难点实施制造执行系统&#xff08;MES&#xff09;涉及多方面的挑战&#xff0c;包括技术、管理和组织层面的问题。以下是常见的难点&#xff1a;数据集成与系统兼容性 MES需要与ERP、PLM、SCADA等系统无缝对接&#xff0c;但不同系统间的数据格式、协议差异可能导…

作者头像 李华