2.架构设计
实现思路
首先针对架构设计,介绍比较常用的几个思路
主动轮询
这是实现定时器最简单粗暴的方式:轮询 + 触发,主要流程有:
注册定时器:按显式的任务执行时间,制定一系列定时任务
节点自轮询:每间隔一个微小的时间范围,对定时任务列表进行全量查询
过滤&触发:以执行时间小于等于当前时刻作为过滤条件,摘出满足执行条件的定时任务进行执行
但这样的定时器需要承担 O(N) 的查询时间复杂度
存储结构优化
有序表
基于有序表提升查询效率
即利用存储结构,将时间复杂度均摊到每一笔操作中。例如使用红黑树或跳表,通过牺牲插入时间复杂度,降低查询时间复杂度
此处选用 Redis ZSet,以定时任务执行时间为 Score 进行有序结构的搭建,实现流程如下:
- 以 Redis ZSet 作为存储介质(即所有元素始终按照 Score 排序好)
- 每次添加定时任务时,执行 ZAdd 动作,以执行时间的时间戳作为排序的键(Score)进行有序结构的搭建
- 每次查询定时任务时,执行 ZRangeByScore 动作,以当前时刻的时间戳加上一个微小偏移量(1s)作为 Score 的左右边界(因为要选择的是某一段时间已经到期需要执行的任务)
横向分治
通过时间范围分片,减少查询设计的任务数量
当每次查询的时候,其实是在查找将要执行的任务,也就是当前时间点以及一段时间片内的任务,这是即将执行的任务,是真正的目标。在此之后的任务在查找过程没有实际用途且增大了数据规模
因此可以将整个时间线按照时间片进行切割,将和当前时刻同属一个时间片的任务视为即将执行的任务,而从下一个时间片开始往后的任务都视为低优先级的定时任务
在具体实现中,我们可以采取1分钟作为分片的范围,实现流程如下:
- 插入每笔定时任务时,根据执行时间推算出所属分钟级范围表达式,如2025-12-22-2:13:26属于2025-12-22-2:13:00 -> 2025-12-22-2:14:00
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 ZALA!

