每日一博-使用环形队列实现高效的延时消息(代码片段)

小小工匠 小小工匠     2022-12-14     289

关键词:


Pre

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

你可能会说


方案A

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

But…

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

  • (1)轮询效率比较低

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


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


方案B

来说下核心思路

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

  • 环形队列。例如可以创建一个大小为3600的环形队列

  • 任务集合。环上每一个格是一个Set

同时,启动一个timer:

  • 每隔1s,timer在环形队列中移动一格

  • 用一个Current Index来标识当前所在的格;

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

  • Cycle-Num:用于标记当第几圈扫描到这个格时,执行任务

  • Task-Function:到时间后需要执行的任务函数

假设当前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)实时性好,精确到秒

每日一博-delayqueue阻塞队列源码解读(代码片段)

...ffer(Ee)出队方法poll()poll(longtimeout,TimeUnitunit)take()peek小结Pre每日一博-延时任务的多种实现方式解读DelayQueue由优先级支持的、基于时间的调度队列,内部使用非线程安全的优 查看详情

rocketmq延时消息实现原理探究(代码片段)

由于日常开发中遇到几次使用延时消息的场景,而且目前业务中使用到的消息中间件有rabbitmq和kafka,对延时消息的支持都不太理想。其中rabbitmq延时消息是通过设置队列ttl+死信exchange实现缺点嘛:每次都得设置两... 查看详情

提升--20---disruptor-----号称最快的消息队列(代码片段)

...资料:观察者模式:Disruptor核心与特点:Disruptor的核心是一个环形的buffer。线性表--07---队列:环形队列:==Disruptor是用数组实现的 查看详情

rabbitmq实现延时队列(代码片段)

...时间,再进行消费.RabbitMQ没有提供延迟队列功能,但是可以使用TTL+DLX来实现延迟队列效果使用场景电商平台下单后,30分钟未支付,取消订单回滚库存;新用户注册成功一周后,发送问候短信等等.延时队列实现模拟电商平台下单后,30... 查看详情

redis异步队列与延时队列(代码片段)

...业的消息中间件提供了很多功能特性,当然他的部署使用维护都是比较麻烦的。如果你对消息队列没那么高要求,想要轻量级的,使用Redis就没错啦。Redis通过list数据结构来实现消息队列.主要使用到如下命令:lpus... 查看详情

利用rabbitmq的死信队列实现延时消息(代码片段)

mq基本的消息模型mq死信队列的消息模型简单的说就是先弄一个正常队列,然后不要设置消费者,接着给这个正常队列绑定一个死信队列,这个死信队列设置方式和正常队列没啥区别。然后监听这个死信队列的消费.一... 查看详情

环形队列-高效定时触发

...效延时触发,我们需要实现两个重要的数据结构:(1)环形队列,例如可以创建一个包含3600个slot的环形队列(本质是个数组)(2)任务集合,环上每一个slot是一个Set<Task>同时,启动一个timer,这个timer每隔1s,CurrentIndex指... 查看详情

rabbitmq:伪延时队列(代码片段)

目录一、什么是延时队列二、RabbitMQ实现三、延时队列的问题四、解决RabbitMQ的伪延时方案ps:伪延时队列先卖个关子,我们先了解下延时队列。一、什么是延时队列所谓延时队列是指消息push到队列后,监听的消费者不能第一时间... 查看详情

rabbitmq实现延时队列-springboot版本(代码片段)

 rabbitmq本身没有实现延时队列,但是可以通过死信队列机制,自己实现延时队列; 原理:当队列中的消息超时成为死信后,会把消息死信重新发送到配置好的交换机中,然后分发到真实的消费队列;步骤:1、创建带有时... 查看详情

rabbitmq延时队列的实现原理和应用实例(代码片段)

...独设置,每条消息的TTL可以不同。如果两种方法一起使用,则消息的TTL以两者之间较小的那个数值为准。2、死信(DeadLetter)队列“死信”是RabbitMQ中的一种消息机制,当你在消费消息时,如果队列里的消... 查看详情

每日一博-review线程池(代码片段)

文章目录Pre核心设计与实现运行机制线程池的生命周期ctl解读ctl的相关方法线程池的状态任务执行机制任务调度任务缓冲任务申请任务拒绝Pre线程池(ThreadPool)是一种基于池化思想管理线程的工具.使用线程池可以带来一... 查看详情

springboot实战项目整合阿里云rocketmq消息队列实现发送普通消息,延时消息(代码片段)

原文地址:Springboot实战项目整合阿里云RocketMQ消息队列实现发送普通消息,延时消息--附代码-学不会丶-博客园一.为什么选择RocketMQ消息队列?(可跳过看三的整合代码实例)首先RocketMQ是阿里巴巴自研出来的&#... 查看详情

rabbitmq---延迟队列,整合springboot(代码片段)

RabbitMQ---消息队列---下半部分延迟队列概念使用场景RabbitMQ中的TTL队列设置TTL消息设置TTL两者的区别整合springbootpom文件配置文件添加Swagger配置类队列TTL代码架构代码实现延时队列优化代码架构图实现Rabbitmq插件实现延迟队列安装... 查看详情

每日一博-threadlocalvsinheritablethreadlocalvstransmittablethreadlocal(代码片段)

文章目录ThreadLocal核心APIThreadLocal类源码分析setgetremove缺陷InheritableThreadLocal源码解析局限性TransmittableThreadLocalTransmittableThreadLocal是什么实现原理测试ThreadLocal位于java.lang包中的ThreadLocal。多线程访问同一个共享变量的时候容易出现... 查看详情

基于rabbitmq实现分布式延时任务调度(代码片段)

一.分布式延时任务传统做法是将延时任务插入数据库,使用定时去扫描,比对任务是否到期,到期则执行并设置任务状态为完成。这种做法在分布式环境下还需要对定时扫描做特殊处理(加分布式锁)避免任务被重复执行。然... 查看详情

教你如何基于redis来实现高性能延时消息队列!(代码片段)

...ntIdint64 Topicstring Bodystring EffectTimetime.Time复制代码EVENT_POOL:使用redis的hash,里面存储了任务事件的完整信息,key=prefix+namespace+topic,field=EventId,val=EventEntity;EVENT_BUCKET:使用redis的zset,里面存储了任... 查看详情

每日一博-java序列化一二事儿(代码片段)

文章目录whatWhy作用常用APIjava.io.Serializablejava.io.Externalizablejava.io.ObjectOutputStreamjava.io.ObjectInputStreamCode实现Serializable接口ObjectOutputStream#writeObject实现序列化ObjectInputStream#readObject方法实现反序 查看详情

每日一博-countdownlatch使用场景分析以及源码分析(代码片段)

文章目录并发编程常用的工具类简介CountDownLatch概述源码分析使用场景使用场景一:模拟高并发并发执行(让多个线程等待)使用场景二:模拟异步执行后回到主线程的业务(让一个线程等待)并发编程常... 查看详情