每日一博 - 使用环形队列实现高效的延时消息

简介: 每日一博 - 使用环形队列实现高效的延时消息

d0fdb2e70e1847b2b9749789048967d3.png

Pre


来个场景: 24小时后将未进行某个Action的业务,执行另外一个动作。 比如 24小时未付款的订单,取消。

你可能会说

89395785d754489f98843d72bb050093.png

方案A


来个定时呗 ,每隔半小时 ,扫描数据库订单表,将完成时间超过24小时的订单,取消掉。

cce5a163221a4561b317ea0d19b32144.png

But…

这方案有些明显的缺点啊,老哥

  • (1)轮询效率比较低
  • (2)时效性不好,假设每小时轮询一次,最坏的情况下,时间误差会达到1小时;

那如何既保证效率的同时,又保证实时性呢?

b41fed49e88f407999ee70c0ed29582e.png


方案B


来说下核心思路

高效延时消息,包含两个重要的数据结构:

  • 环形队列。例如可以创建一个大小为3600的环形队列
  • 任务集合。环上每一个格是一个Set

同时,启动一个timer:

  • 每隔1s,timer在环形队列中移动一格
  • 用一个Current Index来标识当前所在的格;

Task结构中包含两个重要属性:

  • Cycle-Num:用于标记当第几圈扫描到这个格时,执行任务
  • Task-Function:到时间后需要执行的任务函数

0aae981f1e3940879f3ddf977356ac31.png



假设当前Current Index指向第一格,当有延时消息到达之后,例如希望3620秒之后,触发一个延时消息任务:


(1)计算这个Task应该放在哪一个格,现在是在第1格,3610秒之后,应该是第11格,所以这个Task应该加入第11格的Set<Task>中;


(2)计算这个Task的Cycle-Num,由于环形队列是3600格(每秒移动一格,正好1小时),这个任务是3610秒后执行。所以应该绕3610/3600=1圈之后再执行,于是Cycle-Num=1;


Current Index每秒移动一格,当移动到下一格时,遍历这个格的Set,看看每个Task的Cycle-Num是不是0:

  • 如果不是0,说明任务时间还没到,还需要多移动几圈,将Cycle-Num减1;
  • 如果是0,说明到这个Task的执行时间了,取出Task-Funciton丢给工作线程执行,并把这个Task从Set<Task>中删除
Warning : 不要直接用timer线程来执行任务


总结


总体思路就是这个样子,总结下有点

  • (1)效率高,无需再轮询订单表;一个订单,任务只执行一次
  • (2)实时性好,精确到秒


相关文章
|
5月前
|
消息中间件 Java Apache
消息队列 MQ产品使用合集之Broker内存瞬间增大一倍一般是什么导致的
阿里云消息队列MQ(Message Queue)是一种高可用、高性能的消息中间件服务,它允许您在分布式应用的不同组件之间异步传递消息,从而实现系统解耦、流量削峰填谷以及提高系统的可扩展性和灵活性。以下是使用阿里云消息队列MQ产品的关键点和最佳实践合集。
|
6月前
|
存储 消息中间件 算法
精华推荐 |【算法数据结构专题】「延时队列算法」史上非常详细分析和介绍如何通过时间轮(TimingWheel)实现延时队列的原理指南
精华推荐 |【算法数据结构专题】「延时队列算法」史上非常详细分析和介绍如何通过时间轮(TimingWheel)实现延时队列的原理指南
149 1
|
消息中间件 SQL 资源调度
|
存储 算法 Java
【算法数据结构专题】「延时队列算法」史上手把手教你针对层级时间轮(TimingWheel)实现延时队列的开发实战落地(下)
承接上一篇文章【算法数据结构专题】「延时队列算法」史上手把手教你针对层级时间轮(TimingWheel)实现延时队列的开发实战落地(上)】我们基本上对层级时间轮算法的基本原理有了一定的认识,本章节就从落地的角度进行分析和介绍如何通过Java进行实现一个属于我们自己的时间轮服务组件,最后,在告诉大家一下,其实时间轮的技术是来源于生活中的时钟。
140 1
【算法数据结构专题】「延时队列算法」史上手把手教你针对层级时间轮(TimingWheel)实现延时队列的开发实战落地(下)
|
消息中间件 Java 数据库
RibbitMQ学习笔记延迟队列(一)
RibbitMQ学习笔记延迟队列
68 0
|
消息中间件 存储 NoSQL
RibbitMQ学习笔记延迟队列(二)
RibbitMQ学习笔记延迟队列
90 0
|
消息中间件 缓存 NoSQL
每日一博 - 延时任务的多种实现方式解读
每日一博 - 延时任务的多种实现方式解读
263 0
|
消息中间件 Java Kafka
15、RabbitMQ没有延时队列?学会这一招玩转延时队列
15、RabbitMQ没有延时队列?学会这一招玩转延时队列
245 0
15、RabbitMQ没有延时队列?学会这一招玩转延时队列
|
存储 消息中间件 NoSQL
一口气说出 6 种实现延时消息的方案,还有谁不会?!
一口气说出 6 种实现延时消息的方案,还有谁不会?!
【异步FIFO的一些小事·3】异步FIFO中指针走线延时的一些思考
【异步FIFO的一些小事·3】异步FIFO中指针走线延时的一些思考
145 0
【异步FIFO的一些小事·3】异步FIFO中指针走线延时的一些思考