Nginx中信号与定时器均在事件循环控制点同步处理,执行顺序为:先检查信号、再检查定时器、最后处理I/O事件;二者无抢占式优先级,响应时机取决于内核通知与循环调度。

Nginx 的事件循环本身不直接处理信号量(signal)和定时任务(timer),它们是通过操作系统机制与主事件循环协同工作的,**优先级关系不是由 Nginx 主动调度决定的,而是由内核通知时机和 Nginx 的响应顺序隐式体现的**。
信号处理:异步通知,高响应性但不抢占事件循环
Nginx 使用 sigwaitinfo() 或 signalfd()(Linux)等方式在事件循环中同步等待信号,而非依赖传统异步信号处理(signal() + SIGUSR1 等)。这意味着:
- 信号不会中断正在执行的事件回调(如 accept、read、write),而是被暂存,等当前事件处理完成、回到
epoll_wait()(或 kqueue)之前才统一检查; - 信号处理函数(如
ngx_signal_handler)运行在主线程、主事件循环上下文中,属于“同步响应”,但延迟极低(通常一个事件周期内); - 常见信号如
TERM、QUIT、HUP触发后,Nginx 会标记状态(如ngx_terminate、ngx_reconfigure),并在下一次事件循环迭代中执行对应逻辑(如关闭监听、重载配置),不立即终止当前请求。
定时任务(Timer):基于红黑树管理,精度依赖系统时钟与事件驱动模型
Nginx 使用红黑树维护所有定时器(ngx_event_timer_rbtree),每次调用 epoll_wait() 时传入最近超时时间作为 timeout 值。其行为特点是:
- 定时器到期不触发中断,而是在
epoll_wait()返回后、处理就绪事件前,由ngx_event_expire_timers()扫描并执行已超时的 timer handler; - 定时器回调(如清理空闲连接、更新统计)与网络事件回调处于同一调度层级,无固有优先级高低之分——谁先到谁先处理,但 timer 检查总在 I/O 事件处理之前;
- 最小分辨率取决于系统调用精度(如
epoll_wait的 timeout 参数支持毫秒级),实际定时误差通常在 1–10ms 范围,不适合微秒级实时任务。
信号与定时器在事件循环中的实际执行顺序
一个典型的 Nginx 事件循环迭代步骤如下(简化):
- 检查是否有待处理信号 → 若有,执行信号处理器(如 reload、shutdown 标记);
- 检查定时器红黑树 → 若有超时,执行所有到期 timer 回调;
- 调用
epoll_wait()(带最小 timeout)等待 I/O 事件; - 处理就绪的读写、accept 等事件;
- 回到第一步,开始下一轮。
因此,在单次循环中:**信号响应 ≈ 定时器检查 > I/O 事件处理**。但要注意:信号本身是内核异步投递的,Nginx 只保证“尽快同步响应”,并不比定时器更“优先”;真正影响行为的是「何时被检测到」和「后续动作是否阻塞」。
开发者需注意的关键点
如果你在模块中添加自定义 timer 或处理信号:
- 避免在 signal handler 中做耗时操作(如文件 I/O、内存分配),应仅设标志位,由主循环后续处理;
- 定时器回调也应轻量,否则会拖慢整个事件循环;Nginx 不提供 timer 优先级队列,所有 timer 平权;
- 不要假设 signal 或 timer 会打断 long-polling 或 sendfile 等系统调用——它们只在事件循环控制点生效;
- 调试时可通过
nginx -t -v和日志级别debug_event查看 timer 插入/过期、信号接收等细节。










