Nginx采用多进程+异步非阻塞I/O模型,通过红黑树管理超时事件并结合epoll/kqueue timeout实现定时任务调度,不依赖系统级定时器。

Nginx 并没有传统意义上的“Event Loop”(如 Node.js 那样基于 JavaScript 单线程事件循环),它采用的是**多进程 + 异步非阻塞 I/O 模型**,其定时任务调度逻辑由核心的 event timer 机制驱动,底层依托操作系统提供的高效事件通知(epoll/kqueue/select)和红黑树管理的超时队列。
定时任务本质是「超时事件」的统一管理
Nginx 将所有需要延后执行的操作(如连接超时、请求超时、keepalive 超时、worker 进程定期检查等)都抽象为 ngx_event_t 结构体中的 timer 属性。每个待调度任务被插入到一个全局红黑树(ngx_event_timer_rbtree)中,按超时时间排序。红黑树根节点始终指向最近将要触发的事件,实现 O(log n) 插入/删除 和 O(1) 获取最小超时时间。
- 所有 timer 都由 master/worker 进程各自的 event loop 主动轮询:每次进入
ngx_process_events_and_timers()时,先检查红黑树最小节点是否已超时 - 若超时,则从树中摘下该事件,调用其
handler回调(如ngx_event_expire_timers处理连接超时) - 这个过程不依赖系统级定时器(如
timerfd),而是靠 epoll_wait 的 timeout 参数控制等待时长——即「阻塞等待时间 = 最近 timer 到期剩余时间」
如何添加自定义定时任务
模块开发者可通过 ngx_add_timer() 注册回调,本质上是初始化一个 ngx_event_t 并插入红黑树:
- 分配并零初始化一个
ngx_event_t变量(通常作为模块静态变量或结构体内嵌) - 设置
ev->handler = your_handler,并在 handler 中完成业务逻辑后调用ngx_del_timer(ev)或再次ngx_add_timer(ev, delay)实现周期性调度 - 必须确保 event 在生命周期内有效(不能指向栈变量),且避免重复添加(需检查
ev->timedout或ev->timer_set)
与系统 timer 的关系:无主动创建,只复用 epoll/kqueue timeout
Nginx 不使用 setitimer、timerfd_create 或 POSIX timers。它的「定时精度」取决于:
– epoll_wait/kqueue 的 timeout 参数(毫秒级)
– worker 进程是否繁忙(若 CPU 密集型操作过长,可能延迟响应 timer)
– 所有 timer 共享同一套机制,不存在独立线程或信号中断
- 例如配置
keepalive_timeout 65,Nginx 会在客户端空闲时为该连接事件设置 65s 后触发的 timer;到期后调用ngx_http_set_keepalive关闭连接 - 第三方模块如
nginx-rtmp-module的心跳检测、lua-nginx-module的ngx.timer.at(),底层也都映射到这套红黑树+epoll timeout 机制
注意:这不是「任务队列」,也不支持优先级或取消语义
Nginx timer 是轻量、低开销的超时通知,设计目标是网络连接生命周期管理,不是通用任务调度器:
- 无法在运行时动态调整已添加 timer 的超时时间(需先 del 再 add)
- 不提供类似 cron 的表达式解析或秒级以下精度(最小单位为毫秒,但实际受事件循环频率限制)
- 没有任务取消回调或上下文传递机制,需模块自行维护状态
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/xitongjiaocheng/123727.html