ngx_worker_process_cycle
1 定义ngx_worker_process_cycle 函数 定义在 ./nginx-1.24.0/src/os/unix/ngx_process_cycle.cstaticvoidngx_worker_process_cycle(ngx_cycle_t*cycle,void*data){ngx_int_tworker(intptr_t)data;ngx_processNGX_PROCESS_WORKER;ngx_workerworker;ngx_worker_process_init(cycle,worker);ngx_setproctitle(worker process);for(;;){if(ngx_exiting){if(ngx_event_no_timers_left()NGX_OK){ngx_log_error(NGX_LOG_NOTICE,cycle-log,0,exiting);ngx_worker_process_exit(cycle);}}ngx_log_debug0(NGX_LOG_DEBUG_EVENT,cycle-log,0,worker cycle);ngx_process_events_and_timers(cycle);if(ngx_terminate){ngx_log_error(NGX_LOG_NOTICE,cycle-log,0,exiting);ngx_worker_process_exit(cycle);}if(ngx_quit){ngx_quit0;ngx_log_error(NGX_LOG_NOTICE,cycle-log,0,gracefully shutting down);ngx_setproctitle(worker process is shutting down);if(!ngx_exiting){ngx_exiting1;ngx_set_shutdown_timer(cycle);ngx_close_listening_sockets(cycle);ngx_close_idle_connections(cycle);ngx_event_process_posted(cycle,ngx_posted_events);}}if(ngx_reopen){ngx_reopen0;ngx_log_error(NGX_LOG_NOTICE,cycle-log,0,reopening logs);ngx_reopen_files(cycle,-1);}}}ngx_worker_process_cycle 是 Nginx worker 进程的主循环函数 核心作用如下 初始化 worker 进程设置进程身份、调用模块初始化、设置进程标题。 进入事件驱动循环 反复调用 ngx_process_events_and_timers 处理网络 I/O 事件和定时器事件是请求处理的核心驱动。 响应信号实现进程控制 SIGQUIT触发优雅关闭关闭监听、等待现有请求完成后再退出。 SIGTERM立即强制退出。 SIGUSR1重新打开日志文件支持日志轮转。 管理 worker 退出在优雅关闭模式下监测连接与定时器状态确保安全退出。2 详解1 函数签名staticvoidngx_worker_process_cycle(ngx_cycle_t*cycle,void*data)返回值 函数不返回任何值 worker 进程的主循环是一个永不返回的无限循环for (;;) 只有在进程退出时才会通过调用 ngx_worker_process_exit() 等函数直接终止进程。 因此该函数不需要向调用者返回执行结果。参数 ngx_cycle_t *cycle 指向当前运行周期上下文 void *data worker 进程的序号从 0 开始以 intptr_t 整数类型强制转换为 void* 传入 通过 void* 可以传递任意类型的数据结构体指针、整数等增强了接口的通用性2 逻辑流程1 局部变量 2 全局变量 3 初始化 4 修改进程标题 5 事件循环1 局部变量{ngx_int_tworker(intptr_t)data;从通用指针参数 data 中提取出 worker 进程的序号 并赋值给局部变量 worker2 全局变量ngx_processNGX_PROCESS_WORKER;ngx_workerworker;#1 设置全局变量 ngx_process 的值标记当前进程的类型为 Worker NGX_PROCESS_MASTERmaster 进程。 NGX_PROCESS_WORKERworker 进程。 NGX_PROCESS_SINGLE单进程模式。 #2 设置全局变量 ngx_worker 的值保存当前 worker 的编号为何需要同时设置类型和编号 类型 (ngx_process)回答“我是哪类进程”—— 宏观角色。 编号 (ngx_worker)回答“我是该类进程中的哪一个”—— 微观实例。 二者结合完整描述了一个进程在整个 Nginx 多进程架构中的坐标3 初始化ngx_worker_process_init(cycle,worker);Worker 进程启动后执行的第一个核心初始化函数。 它的作用是为 Worker 进程构建一个独立、完整且可运行的环境使其能够处理请求。 如果没有这一步Worker 进程就无法接入 Nginx 的事件驱动架构。4 修改进程标题ngx_setproctitle(worker process);修改了进程在系统中显示的名称 提升可观测性 优化调试体验5 事件循环for(;;){Worker 进程的事件循环主循环。 Worker 进程完成初始化后便进入这个无限循环它交替执行两大任务 处理网络 I/O 与定时器事件以及响应 Master 进程发来的信号指令。if(ngx_exiting){if(ngx_event_no_timers_left()NGX_OK){ngx_log_error(NGX_LOG_NOTICE,cycle-log,0,exiting);ngx_worker_process_exit(cycle);}}#1 检查全局标志位 ngx_exiting 是否为真 ngx_exiting 是整个优雅退出的总开关。一旦被置为 1 意味着 该 Worker 已经不再监听任何端口ngx_close_listening_sockets 已执行。 空闲连接已被主动关闭ngx_close_idle_connections 已执行。 当前正处于等待现有活跃连接自然结束的阶段。 循环位置的意义 该检查放在每次事件循环的最开始 保证了 Worker 在完成上一轮事件处理后 会立即评估是否具备退出条件避免不必要的阻塞等待。#2 if (ngx_event_no_timers_left() NGX_OK) 函数检查事件模块中维护的定时器红黑树是否为空 若定时器树为空没有任何节点返回 NGX_OK。 若定时器树中仍有节点说明还有连接在等待超时事件返回 NGX_ERROR。 定时器与连接的关系 在 Nginx 中几乎每一个活跃的连接都对应一个定时器事件。 退出条件判断逻辑只有当定时器树彻底为空时才能断定 所有连接要么已被正常关闭要么已因超时被处理完毕。 没有任何连接处于“等待未来某个时刻执行超时回调”的状态。 此刻退出进程完全安全不会中断任何尚未完成的请求。#3 日志记录与退出 ngx_log_error在错误日志中写入 [notice] 级别的 exiting 消息。 运维人员可以通过日志确认 Worker 是正常优雅退出的而非异常崩溃。 ngx_worker_process_exit(cycle) 执行 Worker 进程的最终退出动作ngx_log_debug0(NGX_LOG_DEBUG_EVENT,cycle-log,0,worker cycle);记录日志ngx_process_events_and_timers(cycle);Worker 进程主循环中的核心调度器 它负责在一次循环迭代中统一调度和分发网络 I/O 事件与定时器事件if(ngx_terminate){ngx_log_error(NGX_LOG_NOTICE,cycle-log,0,exiting);ngx_worker_process_exit(cycle);}#1 if (ngx_terminate) ngx_terminate全局整型标志变量初始值为 0。 置位时机 当 Worker 进程接收到 SIGTERM 或 SIGINT 信号时 信号处理函数 ngx_signal_handler() 会将该标志置为 1。 检查时机 每次事件循环完成一轮 I/O 和定时器处理后立即检查该标志。#2 ngx_log_error(NGX_LOG_NOTICE, cycle-log, 0, exiting); 向 Nginx 错误日志文件写入一条 [notice] 级别的日志内容为 exiting。 运维人员可通过日志确认 Worker 进程是由于收到 SIGTERM 而退出的而非异常崩溃。#3 ngx_worker_process_exit(cycle); 调用 Worker 进程的退出函数执行以下关键步骤 调用所有模块的 exit_process 回调函数释放模块级资源。 销毁内存池 cycle-pool归还所有分配的内存。 关闭所有打开的文件描述符。 最终调用系统调用 exit(0) 或 _exit(0) 终止进程。if(ngx_quit){ngx_quit0;ngx_log_error(NGX_LOG_NOTICE,cycle-log,0,gracefully shutting down);ngx_setproctitle(worker process is shutting down);if(!ngx_exiting){ngx_exiting1;ngx_set_shutdown_timer(cycle);ngx_close_listening_sockets(cycle);ngx_close_idle_connections(cycle);ngx_event_process_posted(cycle,ngx_posted_events);}}Nginx 优雅关闭机制的启动触发器。 当 Worker 进程收到 SIGQUIT 信号后 该段逻辑会执行一次性的状态切换和资源清理动作 将进程从“正常服务”状态切换为“待退出”状态。#1 第一层条件if (ngx_quit) ngx_quit全局标志变量初始值为 0。 置位时机 当 Worker 进程接收到 SIGQUIT 信号时信号处理函数 ngx_signal_handler() 将其置为 1。 检查时机 在完成本轮 I/O 事件和定时器处理后且在 ngx_terminate 检查和 ngx_reopen 检查之间。 注意该标志仅用于触发优雅关闭的启动动作执行一次后立即被清零 因此该 if 块在整个进程生命周期中最多执行一次。#2 ngx_quit 0; 作用立即将 ngx_quit 标志清零。 逻辑防止后续循环迭代重复进入该 if 块确保优雅关闭的初始化动作只执行一次。 意义这是一种常见的“一次性触发”模式将异步信号转化为一次同步的状态转换。#3 日志与进程标题更新 日志记录 向错误日志写入 [notice] 级别的 gracefully shutting down 明确记录 Worker 进程开始优雅关闭流程。 进程标题 调用 ngx_setproctitle 修改进程名称为 worker process is shutting down。 运维人员通过 ps aux | grep nginx 可直观看到哪些 Worker 正在关闭中提升可观测性。 意义为运维提供了明确的状态可视化便于监控和问题追踪。#4 if (!ngx_exiting) ngx_exiting 全局标志表示进程已经进入待退出状态即优雅关闭流程已启动。 检查目的 确保接下来的清理动作只执行一次。 由于 ngx_quit 被清零ngx_exiting 成为防止重复执行的第二道保险。#5 ngx_exiting 1; 作用将 ngx_exiting 标志置为 1正式宣告进程进入“待退出状态”。 联动效果从下一轮循环开始位于循环头部的 if (ngx_exiting) 检查将每轮执行 持续判断定时器树是否为空直至最终退出。 意义这是优雅关闭流程中的状态切换枢纽 将一次性启动动作与持续性的退出条件检查分离开来。#6 ngx_set_shutdown_timer(cycle); 作用设置一个全局保底定时器。 逻辑该函数通常为空操作但某些模块如 ngx_event_core_module可能会设置一个超时时间 如果 Worker 在指定时间内未能自然退出例如某些连接异常僵死该定时器超时后会强制终止进程。 意义防止因某些异常连接或 Bug 导致 Worker 永远无法退出确保优雅关闭流程终将结束。#7 ngx_close_listening_sockets(cycle); 作用关闭当前 Worker 进程所有的监听套接字。 逻辑 遍历 cycle-listening 数组 对每个监听套接字调用 close() 系统调用并从事件模块如 epoll中移除相关事件。 后果 该 Worker 从此不再接受任何新的客户端连接请求。 意义 这是优雅关闭的核心隔离动作。它切断了新请求的入口 使 Worker 进入“只出不进”的静默状态将资源专注于处理现有连接。#8 ngx_close_idle_connections(cycle); 作用 遍历连接池主动关闭当前空闲的 Keep-Alive 连接。 空闲连接定义 指那些已经完成了一次请求-响应交互、正等待下一次请求的 Keep-Alive 连接 逻辑 对这些连接调用 ngx_close_connection()立即释放资源。 不关闭活跃连接 正在处理请求有读/写事件挂起的连接不会被关闭它们将继续由事件循环处理直至完成。#9 ngx_event_process_posted(cycle, ngx_posted_events); 作用 立即处理 ngx_posted_events 延迟事件队列。 背景 在 ngx_process_events_and_timers 中 一些优先级较低的事件会被放入 ngx_posted_events 队列 通常在当前循环末尾统一处理。 此时主动调用该函数 是为了在开始等待退出之前尽快处理掉这些积压事件推动连接状态向前演变。 意义加速现有请求的处理进程使 Worker 能更快地满足最终退出条件。完整流程串联 从 SIGQUIT 到最终退出 信号到达 → ngx_quit 1异步信号处理函数设置。 主循环检测 → 进入 if (ngx_quit) 块执行上述初始化动作 清零 ngx_quit更新日志和进程标题。 设置 ngx_exiting 1启动保底定时器。 关闭监听端口关闭空闲连接。 立即处理延迟事件队列。 状态转换完成 → Worker 进入“待退出状态”。 后续循环 → 循环头部的 if (ngx_exiting) 检查每轮执行等待定时器树清空。 最终退出 → 定时器树为空时执行 ngx_worker_process_exit。if(ngx_reopen){ngx_reopen0;ngx_log_error(NGX_LOG_NOTICE,cycle-log,0,reopening logs);ngx_reopen_files(cycle,-1);}}}#1 if (ngx_reopen) ngx_reopen全局标志变量初始值为 0。 置位时机 当 Worker 进程接收到 SIGUSR1 信号时信号处理函数 ngx_signal_handler() 会将其置为 1。 检查时机在每次事件循环末尾处理完 ngx_quit 逻辑之后。#2 ngx_reopen 0; 作用 立即将 ngx_reopen 标志清零。 逻辑 防止在下一次循环迭代时重复执行日志重开操作确保一次信号只触发一次实际的 reopen 动作。#3 ngx_log_error(NGX_LOG_NOTICE, cycle-log, 0, reopening logs); 作用 向错误日志文件写入一条 [notice] 级别的日志内容为 reopening logs。 注意 此时写入日志使用的是旧的文件描述符因为重新打开的动作尚未执行。 该日志会出现在日志切割前的旧日志文件中方便运维人员追踪操作时间线。 意义 为运维操作留下审计记录确认信号已被 Worker 进程接收并处理。#4 ngx_reopen_files(cycle, -1); 函数原型 void ngx_reopen_files(ngx_cycle_t *cycle, ngx_uint_t reopen_type); 参数说明 cycle 全局核心结构体包含所有需要重新打开的文件信息。 -1 特殊标志值表示 只重新打开日志文件不重新打开监听套接字。 若传入正值则表示在平滑升级场景中重新打开监听端口。