基于Redis实现的延时队列
基于Redis实现的延时队列
针对于Redis实现延时队列有两种实现方式:
使用zset实现实现的延时队列
借助redis zset来实现延时队列,具体的实现代码很简单,就是从zset中取出score小于当前时间戳的数据
import cn.hutool.json.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;@Component
public class RedisDelayDemo {@Autowiredprivate RedisTemplate redisTemplate;private static final Long DELETE_SUCCESS = 1L;//线程安全setprivate Set<String> topic = new CopyOnWriteArraySet<>();//放入数据public void push(String key, Object val, long delayTime) {topic.add(key);//hutool的json转换工具会有些问题,性能相对来说比较原生的jackson也会差一些 我这边是为了图方便String strVal = val instanceof String ? (String) val : JSONUtil.toJsonStr(val);redisTemplate.opsForZSet().add(key, strVal, System.currentTimeMillis() + delayTime);}//获取数据public String get(String key) {Set<String> sets = redisTemplate.opsForZSet().rangeByScore(key, 0, System.currentTimeMillis(), 0, 3);if (CollectionUtils.isEmpty(sets)) {return null;}for (String val : sets) {if (DELETE_SUCCESS.equals(redisTemplate.opsForZSet().remove(key, val))) {// 删除成功,表示抢占到return val;}}return null;}}
为什么会这么设计?
-
为啥将数据返回包在删除中?
- 如果我们按照正常的实现流程,每次从zset中取一个,在单实例(单机)的情况下这个操作的话是没有问题的,但是你无法保证该情况下就只有一个人拿到了这个数据,在多实例(多机)的场景下,可能存在多个实例同时拿到了它,那我们要如何表示只有一个实例拥有了她呢?此时我们就要借助
redis
的单线程机制,只可能会有一个实例会删除成功,所以拿到并删除成功的那个实例就是幸运儿
- 如果我们按照正常的实现流程,每次从zset中取一个,在单实例(单机)的情况下这个操作的话是没有问题的,但是你无法保证该情况下就只有一个人拿到了这个数据,在多实例(多机)的场景下,可能存在多个实例同时拿到了它,那我们要如何表示只有一个实例拥有了她呢?此时我们就要借助
-
为啥一次取3个数据
- 如果一次只拿一个,那么每次抢占到数据的几率并不太大,特别是当实例比较多时,可能会做多次的无效操作,为了减少这个可能性,所以可以一次多拿几个做备选,具体拿几个这个看你定时任务的时间间隔和具体的业务场景
Demo
final String key = "myzset";
for (int i = 0; i < 10; i++) {redisDelayDemo.push(key, "xiaozhang"+ i, 9000);
}
while (true) {String value = redisDelayDemo.get(key);if (StringUtils.isBlank(value)) {continue;}System.out.println(value);
}
基于Redis过期监听实现延时队列
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;public class RedisExpiredListenter extends KeyExpirationEventMessageListener {private static final Logger LOGGER = LoggerFactory.getLogger(RedisExpiredListenter.class);public RedisExpiredListenter(RedisMessageListenerContainer listenerContainer) {super(listenerContainer);}@Overridepublic void onMessage(Message message, byte[] pattern) {String channel = new String(message.getChannel(), StandardCharsets.UTF_8);//过期的keyString key = new String(message.getBody(),StandardCharsets.UTF_8);LOGGER.info("redis key 过期:pattern={},channel={},key={}",new String(pattern),channel,key);/***你可以将你的内容一起拼接到key中或者可以在redis中存储两个key (例如mykey和mykey_backup)*针对mykey设置过期时间,对于mykey_backup不设置过期时间,这样就可以通过mykey_backup获取到value了**/}}
}
使用Redis
过期监听实现延时队列方法较为便捷,但是该方法也存在一个很大的问题
因为当过期的key数量高于一个阈值的时候, Redis
不能确保 key 在指定时间被删除 , 也就造成了消息可能比你设置的延时时间更长
所以如果你的系统针对于延时队列这个时间要求十分严格,并且在同一时间内会有多个消息需要发生那我就不推荐使用Redis
的延时队列,如果你的系统对于该业务并没有如此严格的要求,并且数量不多的情况下是可以使用的。
使用Redis
实现延时队列还有一个比较大的问题,他并不像消息队列一样保证送达。当订阅事件的客户端会丢失所有在断线期间所有分发给它的事件。 这个问题也是开发者需要考虑的,根据自己的业务场景去判断。
相关文章:

基于Redis实现的延时队列
基于Redis实现的延时队列 针对于Redis实现延时队列有两种实现方式: 使用zset实现实现的延时队列 借助redis zset来实现延时队列,具体的实现代码很简单,就是从zset中取出score小于当前时间戳的数据 import cn.hutool.json.JSONUtil; impor…...

(3.16——3.19)本周后半段总结
周四(3.16) 1.封装了TitleTip组件,并写了博客记录 http://t.csdn.cn/DAY4chttp://t.csdn.cn/DAY4c2.菜单跳转配置完毕,进行了一些页面的细节样式修改 3.基本写完了ServerSideEncryption页面,十一点多剩最后一点交互的…...

C++ 基础: cin和getline() 有啥区别?
所谓温故而知新,所以时不时会回头来看看我们最最基础的知识。 获取标准键盘输入的方法有多种。以C语言来说,最常用的就是cin 和geline() 。那么它们之间有什么区别呢,我们总结一下。 一、cin和geline的异同点 在 C 中,cin 和 ge…...

在使用fastjson中遇到的问题
一、在使用fastjson中遇到的问题 导论:最近在写一个JavaFx项目的时候使用到了fastjson作为处理json数据的依赖。在其它非JavaFx项目中也使用到了相同版本的fastjson,但是可以正常运行,而在JavaFx项目中却报异常,刚开始以为是我的依…...

C++造轮子飙车现场之无锁、有锁环形队列实现
先看带锁的实现。 带锁版本 circular_queue.h // 头文件防卫 #ifndef CIRCULAR_QUEUE_H #define CIRCULAR_QUEUE_H#include <mutex> // 互斥量 #include <condition_variable> // 条件变量template <typename T> class CircularQueue { public:// 构造函数…...

Spring Profiles and @Profile
1. Overview In this tutorial, we’ll focus on introducing Profiles in Spring. Profiles are a core feature of the framework — allowing us to map our beans to different profiles — for example, dev, test, and prod. We can then activate different profiles…...

数据分析-数据探索
文章目录前言主要内容总结更多宝藏前言 😎🥳😎🤠😮🤖🙈💭🍳🍱 随着大数据和人工智能技术的不断发展,数据分析已经成为了一种非常重要的技能和工…...

7个最受欢迎的Python库,大大提高开发效率
当第三方库可以帮我们完成需求时,就不要重复造轮子了 整理了GitHub上7个最受好评的Python库,将在你的开发之旅中提供帮助 PySnooper 很多时候时间都花在了Debug上,大多数人呢会在出错位置的附近使用print,打印某些变量的值 这个…...

Intellij IDEA 中调试 maven 插件
Intellij IDEA 中调试 maven 插件话痨一下步骤1. classfinal-demo 项目部分2. ClassFinal 部分参考资料话痨一下 目前有两个项目: ClassFinal 是一款java class文件安全加密工具。classfinal-demo 是我建的一个Demo,用来测试ClassFinal的加密效果。 目…...

Java全栈知识(1)缓存池
我们先看这么一道题 Integer x new Integer(123); Integer y new Integer(123); System.out.println(x y); // false Integer z 123; Integer k 123; System.out.println(z k); // true Integer a 200; Integer b 200; System.out.println(z k); //false 我们…...

网络安全的特性
0x00 前言 网络安全的特性包括,机密性,完整性,可用性,真实性和不可否认性。详细的内容可以参考如下的内容。 Xmind资源请下载~ 0x01 机密性 机密性(Confidentiality) 意味着阻止未经授权的实体&#x…...

YOLOv8 多目标跟踪
文章大纲 简介环境搭建代码样例跟踪原理代码分析原始老版实现新版本封装代码实现追踪与计数奇奇怪怪错误汇总lap 安装过程报错推理过程报错参考文献与学习路径简介 使用yolov8 做多目标跟踪 文档地址: https://docs.ultralytics.com/modes/track/https://github.com/ultralyt…...

Gitee搭建个人博客(Beautiful Jekyll)
目录一、引言二、博客模板选型 - Jekyll三、安装Jekyll环境3.1 安装Ruby3.2 安装Jekyll3.3 下载Jekyll主题四、搭建我的Gitee博客4.1 选择主题 - Beautiful Jekyll4.2 创建Gitee账号同名代码库4.3 写博客4.4 开通Gitee Pages服务五、对Beautifu Jekyll的相关优化一、引言 之前…...

图形视图框架 事件处理(item)
在图形界面框架中的事件都是先由视图进行接收,然后传递给场景,再由场景传递给图形项。通过键盘处理的话,需要设置焦点,在QGraphicsScene中使用setFoucesItem()函数可以设置焦点,或者图形项使用s…...

PTA第六章作业详解
🚀write in front🚀 📝个人主页:认真写博客的夏目浅石. 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝 📣系列专栏:夏目的作业 💬总结:希望你看完之后&am…...

Java课程设计项目--音乐视频网站系统
一、功能介绍 随着社会的快速发展,计算机的影响是全面且深入的。人们生活水平的不断提高,日常生活中人们对音乐方面的要求也在不断提高,听歌的人数更是不断增加,使得音乐网站的设计的开发成为必需而且紧迫的事情。音乐网站的设计主…...

FPGA可以转IC设计吗?需要学习哪些技能?
曾经在知乎上看到一个回答“入职做FPGA,后续是否还可以转数字IC设计?” 从下面图内薪资就可以对比出来,对比FPGA的行业薪资水平,IC行业中的一些基础性岗位薪资比很多FPGA大多数岗位薪资都要高。 除了薪资之外更多FPGA转IC设计的有…...

初探Gradle
目录一.概述二.优点三.安装与配置1. 官网下载2. 配置环境变量3. 检验4. 配置国内镜像(可选)5. IDEA配置三.工程结构四.生命周期1.Initialization阶段2.Configuration阶段3.Execution阶段五.Task六.常用任务指令七.引入依赖1.本地依赖2.项目依赖3.直接依赖八.依赖类型九.插件十.…...

国产数据库介绍
人大金仓 Kingbase 北京人大金仓信息技术股份有限公司于1999年由中共人民大学专家创立,自成立以来,始终立足自主研发,专注数据管理领域,先后承担了国家“863”、“核高基”等重大专项,研发出了具有国际先进水平的大型…...

Java OpenJudge-test3
目录 1:明明的随机数 2:合影效果 3:不重复的单词 4:和为给定数 5:字符串数组排序问题 6:字符串排序 7:求序列中的众数 1:明明的随机数 总时间限制: 1000ms 内存限制: 65536kB 描述 明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性ÿ…...

蓝桥杯刷题冲刺 | 倒计时22天
作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 文章目录1.选数异或2.特殊年份1.选数异或 题目 链接: 选数异或 - 蓝桥云课 (lanqiao.cn) 给定…...

入行 5年,跳槽 3次,我终于摸透了软件测试这行(来自过来人的忠告)
目录 前言 第一年 第二年 第三年 第四年 作为过来人的一些忠告 前言 最近几年行业在如火如荼的发展壮大,以及其他传统公司都需要大批量的软件测试人员,但是20年的疫情导致大规模裁员,让人觉得行业寒冬已来,软件测试人员的职…...

开源时序数据库学习
计划学习使用QuestDB解决大数据日志存储场景。以下是常见引擎比较 比较项目 InfluxDB TimescaleDB OpenTSDB QuestDB 数据模型 Key-Value Relational Key-Value Relational 存储引擎 自主开发的TSI PostgreSQL扩展程序 Apache HBase 自主开发 查询语言 InfluxQ…...

字节测试工程师悄悄告诉我的软件测试、测试开发常用的测试策略与测试手段
目录 前言 测试策略的关注重点 测试策略主要内容 总体测试策略 初级版本测试策略 跟踪测试执行 版本质量评估 后续版本测试策略 发布质量评估 测试手段 前言 测试策略是指在特定环境约束之下,描述软件开发周期中关于测试原则、方法、方式的纲要ÿ…...

我常用的shell 进制转换工具
一、进制的一些基础知识 1. 二进制(binary) 二进制的取值是0和1; 前缀是 0b 2. 八进制(Octal) 八进制的取值是0-7;前缀是 O 3. 十进制(decimal) 十进制的取值是0-9;没有前缀 …...

手写vue(二)响应式实现
名词解释:vm:指Vue实例一、目标效果vue定义(1)新建vm时,可以通过一个data对象,或者data函数,其属性可以通过vm直接访问,而data对象可以通过vm._data获取(2)修…...

mysql数据库常问面试题
1、NOW()和CURRENT_DATE()有什么区别? NOW()命令用于显示当前年份,月份,日期,小时,分钟和秒。 CURRENT_DATE()仅显示当前年份,月份和日期。 2、CHAR和VARCHAR的区别? (1)…...

AI风暴 :文心一言 VS GPT-4
💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! 文心一言 VS GPT-4 文心一言:知识增强大语言模型百度全新一代知识增强大语言模型,文心大模型家族的新成员,能够与人对话互动&#…...

VR全景城市,用720全景树立城市形象,打造3D可视化智慧城市
随着城市化进程的加速,城市之间的竞争也日益激烈。城市管理者们需要寻求新的方式来提升城市的品牌形象和吸引力。在这个过程中,VR全景营销为城市提供了一种全新的营销手段,可以帮助提升城市的价值和吸引力。一、城市宣传新方式VR全景营销是一…...

javaweb窗口服务人员分析评价系统ssh
A)后台管理员模块:通过该功能模块,管理员可以修改自己的密码,并对管理员进行添加和删除操作。 B)注册用户模块:通过该功能模块,管理员可以查看注册用户的基本信息,对存在问题的用户进…...