当前位置: 首页 > article >正文

如何实现一个延迟队列?

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 不会帮你重发。这就意味着任务会直接丢失无法保证可靠性。此外开启键空间通知会带来额外的性能开销。

相关文章:

如何实现一个延迟队列?

1. 基于 Sorted Set (ZSet) 的实现 这是最轻量级、最原生的 Redis 延迟队列实现方式。 核心思想:利用 ZSet 可以根据 score 进行排序的特性。我们将任务的预期执行时间戳作为 score,任务的具体内容(或任务 ID)作为 member。 生产…...

终极智能修复:VisualCppRedist AIO一键解决Windows软件兼容性问题 [特殊字符]

终极智能修复:VisualCppRedist AIO一键解决Windows软件兼容性问题 😊 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 还在为软件打不开、…...

QMCDecode:打破音乐枷锁,让QQ音乐文件在你的设备上自由呼吸

QMCDecode:打破音乐枷锁,让QQ音乐文件在你的设备上自由呼吸 【免费下载链接】QMCDecode QQ音乐QMC格式转换为普通格式(qmcflac转flac,qmc0,qmc3转mp3, mflac,mflac0等转flac),仅支持macOS,可自动识别到QQ音乐下载目录&…...

Simulink仿真数据管理指南:如何用Logging和Timetable格式进行高效后处理与可视化

Simulink仿真数据管理进阶:从Logging到自动化分析流水线设计 在工程仿真领域,数据管理往往成为制约效率提升的隐形瓶颈。当Simulink模型复杂度超过200个信号节点时,传统的"运行-导出-手动处理"模式会消耗工程师40%以上的时间在数据…...

aiomultiprocess 完全指南:突破 Python GIL 限制的终极并发解决方案

aiomultiprocess 完全指南:突破 Python GIL 限制的终极并发解决方案 【免费下载链接】aiomultiprocess Take a modern Python codebase to the next level of performance. 项目地址: https://gitcode.com/gh_mirrors/ai/aiomultiprocess 在 Python 编程世界…...

嵌入式开发实战:手把手教你用U-Boot命令调试i.MX6ULL开发板(含网络/EMMC操作)

嵌入式开发实战:i.MX6ULL开发板U-Boot调试全攻略 1. 从零开始的硬件调试环境搭建 拿到i.MX6ULL开发板的第一件事,就是建立可靠的调试环境。不同于桌面开发,嵌入式系统往往需要通过串口与开发板交互。这里推荐使用USB转TTL模块连接开发板的调试…...

【2024独家首发】Red Cabbage印相参数矩阵表:17组实测--no stylize值×--sref权重×色域压缩阈值,精准复现植物染料氧化还原曲线

更多请点击: https://intelliparadigm.com 第一章:Red Cabbage印相的化学机理与Midjourney参数映射原理 花青素的pH响应性与图像显影基础 红甘蓝(Red Cabbage)提取液富含花青素(anthocyanin),…...

CANN/asc-devkit asc_select矢量选择函数

asc_select 【免费下载链接】asc-devkit 本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。 项目地址: https://gitcode.com…...

WhisperPlus自动字幕生成:为视频添加多语言字幕的简单方法

WhisperPlus自动字幕生成:为视频添加多语言字幕的简单方法 【免费下载链接】whisper-plus WhisperPlus: Faster, Smarter, and More Capable 🚀 项目地址: https://gitcode.com/gh_mirrors/wh/whisper-plus WhisperPlus是一款功能强大的工具&…...

AI-Trader性能优化:提升AI代理交易速度的10个终极技巧

AI-Trader性能优化:提升AI代理交易速度的10个终极技巧 【免费下载链接】AI-Trader "AI-Trader: 100% Fully-Automated Agent-Native Trading" 项目地址: https://gitcode.com/GitHub_Trending/aitrad/AI-Trader AI-Trader作为100%全自动化的AI代理…...

Gemini在Android Automotive OS上的首次深度集成(车规级低延迟通信协议逆向分析+CAN总线AI指令映射表)

更多请点击: https://intelliparadigm.com 第一章:Gemini在Android Automotive OS上的首次深度集成(车规级低延迟通信协议逆向分析CAN总线AI指令映射表) Google Gemini模型通过定制化Android Automotive OS(AAOS&…...

Apache Airflow 系列教程 | 第30课:Deadline 与 SLA 管理

导读(Introduction) 在生产环境中运行的数据管道,"按时完成"往往和"正确完成"同样重要。当一个关键的每日报表管道必须在早上 8 点前完成,或者当一个下游系统依赖的数据必须在特定时间窗口内准备就绪时,仅仅依靠"失败后告警"是不够的——我…...

别再死记硬背了!Vivado伪双口RAM的wea/ena信号,这次用仿真波形给你讲透

深入解析Vivado伪双口RAM控制信号:从波形图看wea/ena关键设计 在FPGA开发中,存储器设计一直是性能优化的关键环节。Xilinx Vivado工具链提供的伪双口RAM IP核因其灵活性和高效性,成为许多高速数据处理系统的首选方案。然而,不少开…...

从源码细节看muduo为何比libevent2快70%:一次4096字节读取限制引发的性能思考

从缓冲区设计揭秘高性能网络库的优化哲学 在构建高并发服务器时,网络库的性能差异往往源于看似微小的设计决策。当两个知名网络库在相同硬件条件下出现70%的吞吐量差距时,这个数字背后隐藏的是对系统调用、内存管理和数据流控制的深刻理解差异。本文将从…...

Apache Airflow 系列教程 | 第28课:Backfill 与数据回填策略

导读(Introduction) 欢迎来到 Apache Airflow 源码深度解析系列的第二十八课。 在数据工程的日常工作中,“回填”(Backfill)是一个高频操作。当你修复了一个数据转换逻辑的 bug、新增了一个数据列的计算、或者需要重新处理因上游系统故障导致的历史缺失数据时,你需要让…...

SAP供应商创建后,BP界面贸易伙伴字段不显示?手把手教你用FS_API_BP001_CHANGE补传数据

SAP供应商创建后BP界面贸易伙伴字段不显示的解决方案 在SAP系统中创建供应商时,经常会遇到一个令人困惑的问题:明明已经通过标准BAPI(如vmd_ei_api)将贸易伙伴信息成功写入数据库表LFA1的VBUND字段,但在业务伙伴(BP)界…...

门电路的电气特性详解

门电路的电气特性详解 深入理解门电路的电气参数,是设计可靠数字系统的必备知识。 🎯 本章学习要点 理解输入/输出电压阈值参数掌握扇入扇出的概念和计算了解传输延迟对电路的影响理解功耗来源及优化策略 1️⃣ 输入输出特性参数 1.1 电压阈值参数 &a…...

如何彻底解决Windows风扇控制难题:Fan Control完整指南

如何彻底解决Windows风扇控制难题:Fan Control完整指南 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending/f…...

手把手复现1G通话:用Python模拟FM调制、FSK信令与FDMA多用户通信

手把手复现1G通话:用Python模拟FM调制、FSK信令与FDMA多用户通信 在移动通信的演进史中,1G系统如同数字时代的罗塞塔石碑,用模拟信号承载了人类首次无线对话的自由。今天我们将穿越回1983年摩托罗拉DynaTAC 8000X面世的年代,用Py…...

高级技巧:利用SharpShooter实现COM Staging和应用程序白名单绕过

高级技巧:利用SharpShooter实现COM Staging和应用程序白名单绕过 【免费下载链接】SharpShooter Payload Generation Framework 项目地址: https://gitcode.com/gh_mirrors/sh/SharpShooter SharpShooter 是一款功能强大的Payload生成框架,专为安…...

告别激活烦恼:KMS_VL_ALL_AIO智能激活脚本的终极解决方案

告别激活烦恼:KMS_VL_ALL_AIO智能激活脚本的终极解决方案 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 你是否曾经为Windows系统激活而烦恼?或者为Office办公软件的激活…...

Gridfinity Rebuilt OpenSCAD优化技巧:节省材料、提升打印质量的7个方法

Gridfinity Rebuilt OpenSCAD优化技巧:节省材料、提升打印质量的7个方法 【免费下载链接】gridfinity-rebuilt-openscad A ground-up rebuild of the stock gridfinity bins in OpenSCAD 项目地址: https://gitcode.com/gh_mirrors/gr/gridfinity-rebuilt-opensca…...

如何轻松解密Widevine加密视频:完整免费指南

如何轻松解密Widevine加密视频:完整免费指南 【免费下载链接】video_decrypter Decrypt video from a streaming site with MPEG-DASH Widevine DRM encryption. 项目地址: https://gitcode.com/gh_mirrors/vi/video_decrypter 还在为付费视频无法离线保存而…...

如何3步解决网页数学公式复制到Word的世纪难题?

如何3步解决网页数学公式复制到Word的世纪难题? 【免费下载链接】LaTeX2Word-Equation Copy LaTeX Equations as Word Equations, a Chrome Extension 项目地址: https://gitcode.com/gh_mirrors/la/LaTeX2Word-Equation 你是否曾为了将维基百科、学术论文或…...

Verilog分频器进阶:从6分频到1.5分频的实战设计与波形分析

1. 分频器基础与设计思路 在数字电路设计中,时钟信号就像人的心跳一样重要。分频器的作用,就是把这个"心跳"调整到我们需要的节奏。简单来说,分频器就是把输入时钟的频率降低N倍,得到一个新的时钟信号。比如6分频&#…...

MTCNN级联网络设计精讲:从P-Net到O-Net,看作者如何用‘奇数特征图’和‘重叠池化’提升召回率

MTCNN级联网络架构解密:奇数特征图与重叠池化的工程智慧 人脸检测领域的技术演进始终围绕着两个核心命题:如何在有限计算资源下实现实时检测,以及如何在小目标场景中保持高召回率。2016年问世的MTCNN(Multi-task Cascaded Convol…...

vue3-vant-mobile项目部署指南:Netlify零配置发布终极教程

vue3-vant-mobile项目部署指南:Netlify零配置发布终极教程 【免费下载链接】vue3-vant-mobile An mobile web apps template based on the Vue 3 ecosystem。一个基于 Vue 3 生态系统的移动 web 应用模板,帮助你快速完成业务开发。 项目地址: https://…...

对比 Codex 和 Claude Code

要在使用千问或 DeepSeek 等国产模型的前提下,对比 Codex 和 Claude Code,这已经不是一个简单的“二选一”问题,而是一个关于聪明“组合”的选题。虽然它们的设计理念差别很大,但在国产大模型强大的适配能力和高性价比面前&#x…...

告别杂乱地图标注!Arcgis中标注位置与多边形中心点提取的‘黄金搭档’技巧

告别杂乱地图标注!Arcgis中标注位置与多边形中心点提取的‘黄金搭档’技巧 当你在制作行政区划图或设施分布图时,是否曾被密密麻麻的标注搞得焦头烂额?标注重叠、位置不当、中心点偏移——这些问题不仅影响地图美观,更会降低信息的…...

从零开始:sherpa-onnx跨平台语音识别终极指南

从零开始:sherpa-onnx跨平台语音识别终极指南 【免费下载链接】sherpa-onnx Speech-to-text, text-to-speech, speaker diarization, speech enhancement, source separation, and VAD using next-gen Kaldi with onnxruntime without Internet connection. Support…...