资讯动态

如何实现一个延迟队列?

发布时间:2026/8/15 16:33:44 来源:尧图企业网站定制
1. 基于 Sorted Set (ZSet) 的实现这是最轻量级、最原生的 Redis 延迟队列实现方式。核心思想利用 ZSet 可以根据 score 进行排序的特性。我们将任务的预期执行时间戳作为score任务的具体内容或任务 ID作为member。生产者通过ZADD delay_queue timestamp task_content命令将任务加入队列。消费者开启一个后台线程不断轮询 ZSet。使用ZRANGEBYSCORE delay_queue 0 当前时间戳 LIMIT 0 1获取已经到期的任务。面试加分项防坑指南原子性问题在分布式环境下如果多个消费者同时轮询可能会拿到同一个到期的任务。为了防止任务被重复消费必须保证“获取任务”和“删除任务”这两个步骤的原子性。通常的做法是编写一段Lua 脚本在服务端将ZRANGEBYSCORE和ZREM组合执行。轮询消耗不断的死循环轮询会消耗 CPU 和 Redis 性能。如果获取不到任务建议让线程sleep一小段时间比如 100ms再继续。2. 基于 Redisson 的延迟队列 (RDelayedQueue)在实际的企业级企业开发中我们通常不会去手写 ZSet 和 Lua 脚本而是直接使用成熟的客户端框架 Redisson。核心思想Redisson 提供了一套开箱即用的 API使用体验极其接近 Java 原生的阻塞队列BlockingQueue大幅降低了心智负担。底层原理面试官如果追问“Redisson 底层是怎么做的也是一直轮询吗”你可以这样回答Redisson 的底层其实是对 ZSet 的二次封装但它避免了客户端的盲目轮询。它内部使用了三个结构ZSet存储所有延迟任务、List作为就绪队列、Pub/Sub发布订阅。任务加入时带有延迟时间的任务会先进入 ZSet。Redisson 客户端内部有一个定时任务看门狗/后台线程它会根据 ZSet 中最近一个将要过期的任务的时间计算出一个等待时间。时间一到Redisson 会通过Lua 脚本自动将 ZSet 中到期的任务转移到普通的目标List中。消费端实际上是在对这个List执行BLPOP阻塞读取。这样既保证了实时性又完全避免了无效的 CPU 轮询拉取。3. 基于小顶堆实现基于小顶堆实现延迟队列的核心在于利用小顶堆自动局部排序的特性将执行时间最早即绝对时间戳最小的任务始终维持在堆顶queue[0]。这样可以将获取下一个待执行任务的时间复杂度从O ( n ) O(n)O(n)降至O ( 1 ) O(1)O(1)。总结其核心运行机制主要包含以下四个维度1. 数据定义任务包装存入队列的每个元素必须包含一个绝对触发时间戳。排序规则小顶堆的比较器Comparator严格依据该时间戳进行升序排列。物理存储底层通常采用动态一维数组来实现这棵完全二叉树。2. 入队机制尾部插入 上浮siftUp动作当有新延迟任务加入时直接放置在数组的最末尾树的最后一个叶子节点。调整将新节点与其父节点比较。若新节点的时间戳更小发生得更早则两者交换位置。一路上浮siftUp直到遇到比它更小的父节点或成为堆顶。复杂度O ( log ⁡ n ) O(\log n)O(logn)。3. 出队机制头部取出 下沉siftDown检查线程尝试获取堆顶元素queue[0]并对比当前系统时间。阻塞/唤醒如果堆顶任务未到期线程会计算时间差并陷入阻塞等待若已到期则取出该任务。调整取出堆顶后将数组的最后一个元素强行拉到queue[0]补位。然后让该元素与其左右子节点中较小的一个比较并交换一路下沉siftDown直到恢复小顶堆规则。复杂度O ( log ⁡ n ) O(\log n)O(logn)。4. 并发控制工程化落地的核心在纯数据结构之外高并发下的延迟队列如 Java 的DelayQueue必须解决线程安全和 CPU 调度问题锁机制入队和出队操作都必须由独占锁如ReentrantLock保护保证堆结构修改的原子性。Leader-Follower 模式利用条件变量Condition只让第一个等待的线程Leader精准休眠“距离堆顶任务到期的时间”其余线程Follower无限期挂起。等 Leader 醒来拿走任务后再唤醒下一个线程。这极大避免了 CPU 的无效空转和惊群效应。5. 补充避坑Key 过期监听Keyspace Notifications有时候面试官会主动挖坑“我用 Redis 的 Key 过期监听事件来做延迟队列可以吗”标准回答理论上可以但生产环境极度不推荐。原因Redis 的 Pub/Sub 模型是“发后既忘” (fire-and-forget) 的。当一个 key 过期并触发事件时如果恰好此时消费端服务宕机、重启或者网络抖动这个事件就会彻底丢失Redis 不会帮你重发。这就意味着任务会直接丢失无法保证可靠性。此外开启键空间通知会带来额外的性能开销。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价