在springboot中利用Redis实现延迟队列
文章目录
- 前言
- 一、基本思路
- 二、springboot实现案例
- 三、测试
- 总结
前言
在开发过程中,有很多场景都需要用到延迟队列来解决。目前支持延迟队列的中间件也不少,特别是基于JMS模式下的消息中间件基本上都支持延迟队列。但是有时我们项目规模可能比较小,用不上JMS这些中间件。那么利用Redis也可以实现延迟队列的功能。
一、基本思路
利用Redis来实现延迟队列的主要思路是借助Redis的Sorted Set数据类型来实现。
具体做法是将任务的执行时间作为分数(score),任务的内容作为值(value),将任务按照执行时间排序存储在有序集合中。然后周期性地检查有序集合中的任务,根据当前时间和任务的执行时间来决定是否执行任务。
当需要添加新的延迟任务时,只需将任务的执行时间和内容添加到有序集合中即可。当然,你可能需要一个后台进程或定时任务来不断地检查有序集合,以执行到期的任务。
二、springboot实现案例
根据上面的思路,我们可以直接来写代码,本案例的完整代码点击下载。
首先,确保你的Spring Boot项目中已经配置好了Redis依赖。你可以在pom.xml文件中添加如下依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
然后,创建一个延迟队列管理器(DelayQueueManager)类,用于添加任务到延迟队列和处理到期任务:
package com.test.spring.redisdelayqueue;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import java.util.Set;
/*** @author code-long* @version 1.0.0* @ClassName DelayQueueManager.java* @description*/
@Component
public class DelayQueueManager {private static final String key = "delayQueue";@Autowiredprivate RedisTemplate<String, String> redisTemplate;public void addToDelayQueue(String value, long delayMillis) {redisTemplate.opsForZSet().add(key, value, System.currentTimeMillis() + delayMillis);}public Set<String> getExpiredItems(long currentTime) {return redisTemplate.opsForZSet().rangeByScore(key, 0, currentTime);}public void removeItems(Set<String> items) {redisTemplate.opsForZSet().remove(key, items.toArray());}
}
接下来,我们利用spring的定时任务创建一个定时任务,用于定期检查延迟队列中的到期任务并执行。
同时我们还需要单独创建一个线程来专门处理逻辑,因为如果在定时任务直接处理逻辑可能会导致定时任务阻塞的现象,在这个线程中我们为了保证队列的顺序性,在使用BlockingDeque来模拟一个队列。当然如果你的队列逻辑处理不需要保持顺序性,完全可以使用多线程来处理任务。
具体实现代码:
package com.test.spring.redisdelayqueue;import lombok.extern.slf4j.Slf4j;
import org.h2.util.DateTimeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.text.DateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Set;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;/*** @author code-long* @version 1.0.0* @ClassName RedisDelayQueueApplication.java* @description*/
@SpringBootApplication(scanBasePackages = "com.test.spring.redisdelayqueue")
@EnableScheduling
@Slf4j
@RestController
public class RedisDelayQueueApplication {@Autowiredprivate DelayQueueManager delayQueueManager;@Scheduled(fixedRate = 1000) // 每秒执行一次public void processDelayQueue() {long currentTime = System.currentTimeMillis();Set<String> expiredItems = delayQueueManager.getExpiredItems(currentTime);// 处理到期任务,这里就可以达到延迟队列的模型//如果在这里直接处理逻辑,会影响到定时任务执行不完全的现象,比如一个任务执行需要2秒,那么就会阻塞JOB的执行,所以我们要另外启动一个线程来专门处理逻辑for (String item : expiredItems) {//将过期数据加入到执行队列DelayQueueInstance.getInstance().receive(item);}// 从延迟队列中移除已处理的任务:这里的删除可以放到线程中逻辑执行完成再删除if(!expiredItems.isEmpty()){delayQueueManager.removeItems(expiredItems);}}//应用启动成功后,就启动线程@EventListenervoid listener(ApplicationReadyEvent event) {DelayQueueInstance.getInstance().start();}//模拟入队操作@RequestMapping("/push")@Transactionalpublic String test1(){//模拟一个30秒的延迟队列delayQueueManager.addToDelayQueue("{这里可以使json数据:30}",30000);delayQueueManager.addToDelayQueue("{这里可以使json数据:10}",10000);System.out.println("["+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) +"]添加数据到队列");return "success";}public static void main(String[] args) {SpringApplication.run(RedisDelayQueueApplication.class, args);}
}
三、测试
我们在浏览器中访问或者使用curl调用接口:
curl http://localhost:8881/push
后台打印结果为:
[2024-03-14 22:28:54]添加数据到队列
[2024-03-14 22:29:05]收到数据---{这里可以使json数据:10}
[2024-03-14 22:29:25]收到数据---{这里可以使json数据:30}
我们可以看到,基本上能实现延迟队列的功能,只是这里有一点小小的瑕疵,任务可能会存在1秒的误差,但是这依赖于我们定时任务的循环时间,如果时间越短,误差的时间也就越短,定时任务间隔时间越长,误差也就越大。但1秒误差在实际的业务过程中已经是可以接受的了,对服务器来说性能也可以接受。
总结
使用Redis实现延迟队列的好处包括简单、高效,并且Redis本身就具有持久化和高可用性的特性,使得延迟队列的实现更加可靠。如果项目没有必要上JMS中间件,那么使用Redis是一个不错的方案。
相关文章:
在springboot中利用Redis实现延迟队列
文章目录 前言一、基本思路二、springboot实现案例三、测试总结 前言 在开发过程中,有很多场景都需要用到延迟队列来解决。目前支持延迟队列的中间件也不少,特别是基于JMS模式下的消息中间件基本上都支持延迟队列。但是有时我们项目规模可能比较小&…...
UpGrow评论:AI能将我的Instagram粉丝数增加10倍吗?
UpGrow Review: Can AI Grow My Instagram Followers 10X? 概述 UpGrow是一款专注于Instagram增长的AI驱动型社交媒体工具。它通过其庞大的300多人的网络,先进的定位功能,实时分析以及卓越的客户服务,帮助用户有机地增长Instagram关注者。…...
申请软著提交的演示视频有什么要求
申请软件著作权时,演示视频是一个重要的材料,主要用于展示软件的功能和操作流程。演示视频的要求可能会根据不同的申请机构和项目有所不同,但一般来说,以下是几个常见的要求: 内容完整性:演示视频需要展示…...

mac【启动elasticsearch报错:can not run elasticsearch as root
mac【启动elasticsearch报错:can not run elasticsearch as root 问题原因 es默认不能用root用户启动,生产环境建议为elasticsearch创建用户。 解决方案 为elaticsearch创建用户并赋予相应权限。 尝试了以下命令创建用户,adduser esh 和u…...

面试算法-65-二叉树的层平均值
题目 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。 示例 1: 输入:root [3,9,20,null,null,15,7] 输出:[3.00000,14.50000,11.00000] 解释:第 0 层的…...
Linux: boot: latency启动延迟分析
https://elinux.org/images/6/64/Chris-simmonds-boot-time-elce-2017_0.pdf https://www.hcltech.com/sites/default/files/documents/resources/whitepaper/files/an_insight_to_optimize_embedded_linux_boot_time_performance.pdf 无意看到这个启动延迟分析,虽…...

QT界面制作
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);this->setWindowFlag(Qt::FramelessWindowHint);//接收动图QMovie *mv new QMovie(":/pictrue/th.gif…...

进阶二叉树
目录 二叉树 二叉搜索树 二叉搜索树的定义 二叉搜索树的操作 哈夫曼树 哈夫曼树的定义 哈夫曼树的构造 哈夫曼树的性质 平衡二叉树 平衡二叉树的定义: 平衡二叉树的插入调整 1.LL插入/LL旋转 2.RR插入/RR旋转 3.LR插入/LR旋转 4.RL插入/RL旋转 二叉树…...
无人机拦截
配置yolo CUDA报错 nvcc fatal : Unsupported gpu architecture compute_30.(1)查看显卡匹配型号:https://blog.csdn.net/u013308762/article/details/121658823 (2)查看显卡:nvidia-smi -a 》NVIDIA GeF…...

CSDN 编辑器设置图片缩放和居中
CSDN 编辑器设置图片缩放和居中 文章目录 CSDN 编辑器设置图片缩放和居中对齐方式比例缩放 对齐方式 Markdown 编辑器插入图片的代码格式为 CSDN 的 Markdown 编辑器中插入图片,默认都是左对齐,需要设置居中对齐的话,…...

有哪些工具可以替代Gitbook?这篇文章告诉你
你是否曾经在搜索在线文档创建和共享工具时,遇到了Gitbook? Gitbook 是一个相当出色的工具,具有强大的编辑和发布功能,但也有其不足之处,如使用起来有一定的技术要求,入门门槛较高等。如果你正在寻找Gitbook的替代品&…...

小迪安全43WEB 攻防-通用漏洞任意文件下载删除重装敏感读取黑白审计
#知识点: 1、文件操作类安全问题 2、文件下载&删除&读取 3、白盒&黑盒&探针分析 #详细点: 文件读取:基本和文件下载利用类似 文件下载:利用下载获取源码或数据库配置文件及系统敏感文件为后续出思路 …...

大模型提示学习样本量有玄机,自适应调节方法好
引言:探索文本分类中的个性化示例数量 在自然语言处理(NLP)领域,预测模型已经从零开始训练演变为使用标记数据对预训练模型进行微调。这种微调的极端形式涉及到上下文学习(In-Context Learning, ICL)&…...

Redis监控工具
Redis 是一种 NoSQL 数据库系统,以其速度、性能和灵活的数据结构而闻名。Redis 在许多领域都表现出色,包括缓存、会话管理、游戏、排行榜、实时分析、地理空间、叫车、聊天/消息、媒体流和发布/订阅应用程序。Redis 数据集完全存储在内存中,这…...

低代码表单设计器为企业数字转型强劲赋能!
想要实现数字化转型,创造流程化办公,让企业在信息高速发展的社会中抢占更多市场份额,进一步提升市场竞争力,就需要借助专业的软件平台提高效率。低代码开发平台拥有易操作、灵活、可视化的发展优势,作为一种新型的应用…...
【C#】Conventions(惯例)最佳实践和准则
在C#中,Conventions(惯例)是指编写代码时的一套最佳实践和准则。这些惯例旨在提高代码的可读性、一致性和可维护性。虽然这些惯例不是语言的强制规则,但遵循它们可以使你的代码更加清晰和专业。 以下是一些常见的C#编码惯例: 命名约定: 使用有意义的、描述性的名称。类名和公…...

vue3中使用cesium
vue3中使用cesium Cesium是一个开源的JavaScript库,专门用于创建3D地球和2D地图的Web应用程序。它提供了丰富的功能和工具,使得开发人员能够轻松地构建出高质量的地理空间可视化应用。 1. 安装cesium包 npm install cesium2. 复制node_modules中的Ces…...

arduino ide 开发esp8266注意事项
1.引脚序列号必须是常量来定义,否则会无限重启。 #define p2 2 const int Pin2p2; pinMode(Pin2, OUTPUT); 2.关于wifi的模式,ap,sta,apsta三种模式的初始化必须放在void set_up(){}这个函数里,不能额外搞个自定义函数…...

RTC协议与算法基础 - RTP/RTCP
首先,需要说明下,webrtc的核心音视频传输是通过RTP/RTCP协议实现的,源码位于src/modules/rtp_rtcp目录下: 下面让我们对相关的内容基础进行简要分析与说明: 一、TCP与UDP协议 1.1、TCP协议 TCP为了实现数据传输的可…...
c语言游戏实战(8):飞机大作战
前言: 飞机大作战游戏是一种非常受欢迎的射击类游戏,玩家需要控制一架战斗机在屏幕上移动,击落敌机以获得分数。本游戏使用C语言编写,旨在帮助初学者了解游戏开发的基本概念和技巧。 在开始编写代码之前,我们需要先了…...

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...