高并发下应复用定时器、绑定生命周期、设数量熔断并优先用轻量替代方案。具体包括:用单一定时器+时间轮替代多个settimeout;定时器须与request/socket等实体强关联并及时清除;动态创建时加阈值控制;可用微任务、ttl等减少定时器依赖。

高并发场景下,定时器(setTimeout、setInterval)滥用容易导致内存泄漏和事件循环阻塞。关键不是禁止使用定时器,而是通过复用、集中管理和生命周期控制来限制其无序创建。
用单一定时器替代多个定时器
当业务需要为大量对象(如连接、请求、缓存项)设置超时,避免为每个对象单独调用 setTimeout。改用时间轮(Timing Wheel)或最小堆管理统一调度器。
- 例如:使用
node-timers或task-scheduler等轻量库实现单线程、O(1) 插入的延迟任务队列 - 自己实现时,维护一个按到期时间排序的数组或优先队列,主定时器只监听最近到期任务,到期后批量触发
- 典型场景:WebSocket 连接心跳超时、Redis 缓存失效监听、HTTP 请求限流令牌刷新
绑定定时器到明确的生命周期
所有定时器必须与某个可销毁的实体(如 request、socket、class 实例)强关联,并在该实体结束时主动清除。
使用一条命令部署ProbeChain Rydberg测试网代理节点。自动注册为Agent(NodeType=1),免gas,支持macOS/Linux/Windows。触发词:/r
- 在 Express 中,可在中间件里保存
setTimeoutID 到req.timerId,并在响应结束或错误时调用clearTimeout(req.timerId) - 对 Socket 或 EventEmitter 实例,监听
'close'、'error'、'destroy'事件统一清理相关定时器 - 避免在闭包中隐式持有定时器引用,尤其不要在异步回调里反复
setTimeout却不保存句柄
用信号量或计数器做创建闸门
对确实需要动态创建定时器的场景(如动态任务调度),加一层数量熔断控制。
- 维护全局计数器(如
activeTimers = new Set()),每次创建前检查是否超过阈值(如 1000) - 超限时可拒绝、降级(改用 Promise.delay + 循环轮询)、或写入延迟队列等待空闲
- 配合 Prometheus 暴露
nodejs_active_timers_total指标,用于告警和容量评估
优先选用更轻量的替代方案
很多“需要定时器”的逻辑其实可用其他方式解耦,减少定时器依赖。
- 用
process.nextTick或Promise.resolve().then()做微任务延迟,适合毫秒级非精确调度 - 对固定周期任务(如每 30 秒刷配置),用单个
setInterval+ 时间戳判断是否真正执行,而非重复新建 - 数据库或 Redis 的过期机制(TTL)可替代大量内存中的超时逻辑,把压力交给存储层
不复杂但容易忽略:Node.js 的定时器句柄本身不占大内存,但未清除的定时器会持续持有闭包作用域,引发内存泄漏;监控 process.memoryUsage().heapUsed 和 activeTimers 数量是发现隐患的第一步。










