基于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 描述 明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性ÿ…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
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))…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...