找出事件循环的下一次超时
nginx 事件定时器以到期时间为键放入红黑树,事件循环读取最小键确定等待上限。
相关概念
工程问题#
大量连接的读写超时会不断新增、取消和更新;事件循环需要快速定位最早到期的一批事件。
实际实现#
ngx_event_find_timer 调用 ngx_rbtree_min 得到最小到期时间;过期处理循环删除最小节点,再调用对应事件处理函数。
处理流程#
- 把事件按到期时间加入树
- 最小键减当前时间得到等待时长
- 唤醒后连续取出已到期节点
- 标记 timedout 并执行处理函数
源码片段#
固定版本 · 原文摘录src/event/ngx_event_timer.crelease-1.26.3 · L32–L50
32ngx_msec_t33ngx_event_find_timer(void)34{35 ngx_msec_int_t timer;36 ngx_rbtree_node_t *node, *root, *sentinel;3738 if (ngx_event_timer_rbtree.root == &ngx_event_timer_sentinel) {39 return NGX_TIMER_INFINITE;40 }4142 root = ngx_event_timer_rbtree.root;43 sentinel = ngx_event_timer_rbtree.sentinel;4445 node = ngx_rbtree_min(root, sentinel);4647 timer = (ngx_msec_int_t) (node->key - ngx_current_msec);4849 return (ngx_msec_t) (timer > 0 ? timer : 0);50}ngx_event_find_timer
空树表示无限等待;非空时寻找红黑树最小键,计算距离当前毫秒时间的间隔,并把已经到期的结果钳制为零。这里返回事件循环的等待上限,不会直接执行定时器回调。
完整函数。此版本使用 ngx_rbtree_min 沿左子树查最小值,没有 Linux timerqueue 的最左节点缓存。
收益与取舍#
工程分析带来的收益
- 新增与删除具有对数级树操作成本
- 支持任意事件的取消与重新登记
付出的代价
- 工程分析:指针节点与旋转带来常数开销
- 此实现查最小值需要沿树向左遍历
可比较的选择
有序链表头部即最近到期项,但插入可能线性扫描;QEMU 有可比较案例。
版本与适用范围#
对应 nginx 1.26.3 事件定时器;不是所有超时都需要独立的定时线程。
参考来源#
源码、官方文档与原始论文01
nginx · ngx_event_find_timer / ngx_event_expire_timers
源码release-1.26.3src/event/ngx_event_timer.c · ngx_event_find_timer / ngx_event_expire_timers
相关实现与比较#
4 个相关案例Linux 公平调度将 EEVDF 的资格条件与虚拟截止时间结合,用增强红黑树搜索候选任务。
附源码片段 · 调度与资源分配
hrtimer 通过 timerqueue 的红黑树维护到期顺序,并缓存最早到期节点。
附源码片段 · 调度与资源分配
limit_req 把漏桶计算、红黑树查状态与队列回收组合起来,按配置的 key 管理请求速率。
附源码片段 · 通信与流量
Linux v6.5 的 CFS 将可运行实体按 vruntime 放入红黑树,用加权运行时间作为公平性的基准。
附源码片段 · 调度与资源分配