Redisson - 实现延迟队列
Redisson 延迟队列
Redisson 是基于 Redis 的一款功能强大的 Java 客户端。它提供了诸如分布式锁、限流器、阻塞队列、延迟队列等高可用、高并发组件。
其中,RDelayedQueue 是对 Redis 数据结构的高阶封装,能让你将消息延迟一定时间后再进入消费队列。
延迟队列的组成
Redisson 延迟队列由两个 Redis 队列组成:
RDelayedQueue:延迟元素容器,暂存在 Redis 的 zset 中(按时间排序)
RBlockingQueue(目标队列):当延迟时间到达后,Redisson 会自动将元素移动到这个队列,供消费者消费。
Redisson 内部使用 定时轮询线程 来扫描延迟数据并迁移至目标队列。
原理
Redisson 的 RDelayedQueue 设计巧妙,它并非一个单一的 Redis 数据结构,而是结合了 Redis 的 ZSET (有序集合) 和 List (列表,具体实现为 RBlockingQueue) 来实现的
> 生产者 -- (元素, 延迟时间) --> RDelayedQueue (API)
> |
> | (Redisson 内部)
> V
> +--------------------------------------------------+
> | ZSET (有序集合) |
> | Key: delayed_queue_name_zset |
> | Member: task_id_or_payload |
> | Score: execution_timestamp |
> +--------------------------------------------------+
> ^
> | (Eviction Scheduler 定期扫描)
> | (到期任务)
> V
> +--------------------------------------------------+
> | RBlockingQueue (目标队列,基于 Redis List) |
> | Key: destination_queue_name |
> | Value: task_payload |
> +--------------------------------------------------+
> ^
> |
> | (消费者 take()/poll())
> V 消费者 <---------------------------
Redisson 延迟队列的优势
分布式特性:基于 Redis,天然支持分布式环境,多个生产者和消费者实例可以共享同一个延迟队列系统。
高性能与持久化:依赖 Redis 的高性能特性。如果 Redis 配置了持久化 (AOF/RDB),延迟任务的元数据也能得到持久化保障。
易用性:Redisson 提供了简洁易懂的 API,屏蔽了底层 ZSET 和 List 的复杂操作。
精确度较高:任务的到期判断依赖 Redis 服务器的时间,通常比较准确。
支持任务取消:可以通过 RDelayedQueue.remove(object) 方法从延迟队列中移除尚未到期的任务(前提是任务对象能被正确 equals 比较)。
Redisson队列实践
添加依赖
<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.24.3</version>
</dependency>
Redisson 配置 (application.yml):
spring:
application:name: redisson-delayed-order-app# Redisson 配置 (如果使用 redisson-spring-boot-starter,它会尝试自动配置)# 你也可以提供一个 redisson.yaml 文件或在 Java Config 中配置 RedissonClient Bean# 例如,指定单个 Redis 服务器:redis: # Spring Boot 2.x 使用 spring.redis, Spring Boot 3.x 使用 spring.data.redis# Redisson starter 会尝试使用这些配置,但更推荐使用 Redisson 自身的配置方式# address: redis://127.0.0.1:6379 # Redisson 推荐的格式host: 127.0.0.1port: 6379# database: 0# password:# Redisson 自己的配置方式 (更灵活,可以放在 redisson.yaml 中)
# redisson:
# singleServerConfig:
# address: "redis://127.0.0.1:6379"
# database: 0
# # codec: org.redisson.codec.JsonJacksonCodec # 推荐使用 Jackson 序列化
定义延迟任务处理器(消费者)
@Component
public class OrderCloseConsumer implements InitializingBean {private static final String QUEUE_NAME = "order-close-queue";@Autowiredprivate RedissonClient redissonClient;@Autowiredprivate OrderService orderService;@Overridepublic void afterPropertiesSet() {RBlockingQueue<String> blockingQueue = redissonClient.getBlockingQueue(QUEUE_NAME);RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(blockingQueue);// 启动消费线程Executors.newSingleThreadExecutor().submit(() -> {while (true) {try {String orderSn = blockingQueue.take(); // 阻塞等待orderService.closeOrder(orderSn); // 业务处理log.info("订单超时关闭成功:{}", orderSn);} catch (Exception e) {log.error("延迟关单处理异常", e);}}});}
}
在下单时设置延迟任务
public void createOrder(String orderSn) {// 1. 业务入库逻辑...// 2. 加入延迟队列RBlockingQueue<String> blockingQueue = redissonClient.getBlockingQueue("order-close-queue");RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(blockingQueue);delayedQueue.offer(orderSn, 30, TimeUnit.MINUTES); // 30分钟后执行log.info("订单加入延迟关闭队列:{}", orderSn);
}
关键注意事项
1、序列化 (Codec):
Redisson 默认使用 MarshallingCodec,它要求任务对象实现 java.io.Serializable。
推荐配置 RedissonClient 使用 org.redisson.codec.JsonJacksonCodec,这样任务对象无需实现 Serializable,更灵活且跨语言友好。在 RedissonClient Bean 配置中设置:config.setCodec(new JsonJacksonCodec());
2、幂等性: 消费者的处理逻辑(如 processOrderTimeout)必须是幂等的。即使同一个任务被重复消费(如消费者处理中断后任务重投,或 remove 失败后任务仍到期),最终结果也应一致。通过检查订单当前状态是保证幂等性的关键。
3、任务取消的 equals() 和 hashCode(): RDelayedQueue.remove(object) 依赖于任务对象的 equals() 和 hashCode() 方法来查找并删除。确保任务载体类 (如 OrderTimeoutTask) 正确实现了这两个方法,通常基于任务的唯一标识(如订单号)。
4、消费者线程管理: 使用 InitializingBean 和 DisposableBean 来管理消费者线程的生命周期。消费者逻辑应在单独的线程中执行,避免阻塞主线程。可以使用 Executors 创建线程池来并发处理任务。
5、错误处理与重试: 消费者循环中应有完善的 try-catch 块,处理单个任务失败的情况,避免整个消费者线程挂掉。可以考虑引入失败任务记录、告警或简单的延时重试(但要注意避免无限重试)。
6、Redis 持久化: 为保证系统重启后延迟任务不丢失(ZSET 中的元数据),Redis 服务器应配置 RDB 或 AOF 持久化。
7、消费者并发与伸缩:
可以启动多个消费者实例(不同JVM进程),它们会从同一个目标 RBlockingQueue 中竞争获取任务,实现负载均衡。
在单个消费者实例内部,也可以使用线程池来并发处理从队列中获取的任务。
8、监控: 关注 Redis 中 ZSET 和 List 的长度、Redisson 调度线程的健康状况、任务处理的成功率和耗时等指标,以便及时发现和处理问题。
9、Redisson 版本: 确保使用较新的稳定版 Redisson,因为早期版本可能在延迟队列的某些边缘场景下存在问题。
总结
Redisson 的 RDelayedQueue 通过巧妙地结合 Redis ZSET 和 List,提供了一个强大、易用且高效的分布式延迟队列解决方案。它非常适合如订单超时关闭、延时通知、定时任务等场景。在实践中,务必注意序列化、幂等性、任务取消的正确实现以及消费者端的健壮性设计,才能充分发挥其优势,构建稳定可靠的分布式应用。
相关文章:
Redisson - 实现延迟队列
Redisson 延迟队列 Redisson 是基于 Redis 的一款功能强大的 Java 客户端。它提供了诸如分布式锁、限流器、阻塞队列、延迟队列等高可用、高并发组件。 其中,RDelayedQueue 是对 Redis 数据结构的高阶封装,能让你将消息延迟一定时间后再进入消费队列。…...

软件工程的定义与发展历程
文章目录 一、软件工程的定义二、软件工程的发展历程1. 前软件工程时期(1940s-1960s)2. 软件工程诞生(1968)3. 结构化方法时期(1970s)4. 面向对象时期(1980s)5. 现代软件工程(1990s-至今) 三、软件工程的发展趋势 一、软件工程的定义 软件工程是应用系统化、规范化、可量化的方…...
艾利特协作机器人:重新定义工业涂胶场景的精度革命
品牌使命与技术基因 作为全球协作机器人领域成长最快的企业之一,艾利特始终聚焦于解决工业生产中的人机协作痛点。在汽车制造、3C电子、新能源等领域的涂胶工艺场景中,我们通过自主研发的EC系列协作机器人,实现了: 空间利用率&a…...

第十三节:第五部分:集合框架:集合嵌套
集合嵌套案例分析 代码: package com.itheima.day27_Collection_nesting;import java.util.*;/*目标:理解集合的嵌套。 江苏省 "南京市","扬州市","苏州市","无锡市","常州市" 湖北省 "武汉市","…...

Java设计模式之观察者模式详解
一、观察者模式简介 观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系。当一个对象(主题)的状态发生改变时,所有依赖于它的对象(观察者)都会自…...

freeRTOS 消息队列之一个事件添加到消息队列超时怎么处理
一 消息队列的结构框图 xTasksWaitingToSend:这个列表存储了所有因为队列已满而等待发送消息的任务。当任务尝试向一个已满的队列发送消息时,该任务会被挂起并加入到xTasksWaitingToSend列表中,直到队列中有空间可用, xTasksW…...
十八、【用户认证篇】安全第一步:基于 JWT 的前后端分离认证方案
【用户认证篇】安全第一步:基于 JWT 的前后端分离认证方案 前言什么是 JWT (JSON Web Token)?准备工作第一部分:后端 Django 配置 JWT 认证1. 安装 `djangorestframework-simplejwt`2. 在 `settings.py` 中配置 `djangorestframework-simplejwt`3. 在项目的 `urls.py` 中添加…...
RabbitMQ 开机启动配置教程
RabbitMQ 开机启动配置教程 在本教程中,我们将详细介绍如何配置 RabbitMQ 以实现开机自动启动。此配置适用于手动安装的 RabbitMQ 版本。 环境准备 操作系统:CentOS 7RabbitMQ 版本:3.8.4Erlang 版本:21.3 步骤 1. 安装 Erla…...

Authpf(OpenBSD)认证防火墙到ssh连接到SSH端口转发技术栈 与渗透网络安全的关联 (RED Team Technique )
目录 🔍 1. Authpf概述与Shell设置的作用 什么是Authpf? Shell设置为/usr/sbin/authpf的作用与含义 🛠️ 2. Authpf工作原理与防火墙绕过机制 技术栈 工作原理 防火墙绕过机制 Shell关联 🌐 3. Authpf与SSH认证及服务探测…...

组合与排列
组合与排列主要有两个区别,区别在于是否按次序排列和符号表示不同。 全排列: 从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当mn时所有的排列情况…...
神经网络-Day45
目录 一、tensorboard的基本操作1.1 发展历史1.2 tensorboard的原理 二、tensorboard实战2.1 cifar-10 MLP实战2.2 cifar-10 CNN实战 在神经网络训练中,为了帮助理解,借用了很多的组件,比如训练进度条、可视化的loss下降曲线、权重分布图&…...
【西门子杯工业嵌入式-1-基本环境与空白模板】
西门子杯工业嵌入式-1-基本环境与空白模板 项目资料一、软件安装与环境准备1. 安装MDK52. 安装驱动3. 安装GD32F470支持包 二、工程目录结构建议三、使用MDK创建工程流程1. 新建工程2. 添加工程组(Group)3. 添加源文件 四、编译配置设置(Opti…...

Apache Druid
目录 Apache Druid是什么? CVE-2021-25646(Apache Druid代码执行漏洞) Apache Druid是什么? Apache Druid是一个高性能、分布式的数据存储和分析系统。设计用于处理大量实时数据,并进行低延迟的查询。它特别适合用于分析大规模日志、事件数据…...

使用深蓝词库软件导入自定义的词库到微软拼音输入法
我这有一个人员名单,把它看作一个词库,下面我演示一下如何把这个词库导入微软输入法 首先建一个text文件,一行写一个词条 下载深蓝词库 按照我这个配置,点击转换,然后在桌面微软输入法那右键,选择设置 点…...
Docker快速部署AnythingLLM全攻略
Docker版AnythingLLM安装指南 环境准备 确保已安装: Docker Engine 20.10.14+Docker Compose 2.5.0+验证安装: docker --version && docker compose version安装步骤 创建持久化存储目录: mkdir -p ~/anythingllm/database ~/anythingllm/files运行容器(基础配置)…...

使用Node.js分片上传大文件到阿里云OSS
阿里云OSS的分片上传(Multipart Upload)是一种针对大文件优化的上传方式,其核心流程和关键特性如下: 1. 核心流程 分片上传分为三个步骤: 初始化任务:调用InitiateMultipartUpload接口创建上传任务…...
高性能分布式消息队列系统(四)
八、客户端模块的实现 客户端实现的总体框架 在 RabbitMQ 中,应用层提供消息服务的核心实体是 信道(Channel)。 用户想要与消息队列服务器交互时,通常不会直接操作底层的 TCP 连接,而是通过信道来进行各种消息的发布…...
C#异步编程:从线程到Task的进化之路
一、没有异步编程之前的时候 在异步编程出现之前,程序主要采用同步编程模型。这种模型下,所有操作按顺序执行,当一个操作(如I/O读写、网络请求)阻塞时,整个程序会被挂起,导致资源利用率低和响应延迟高。具体问题包括: 阻塞执行:同步代码在执行耗时操作时(如文件读取…...
[论文阅读] 人工智能+软件工程 | 用大模型优化软件性能
用大模型优化软件性能?这篇论文让代码跑出新速度! arXiv:2506.01249 SysLLMatic: Large Language Models are Software System Optimizers Huiyun Peng, Arjun Gupte, Ryan Hasler, Nicholas John Eliopoulos, Chien-Chou Ho, Rishi Mantri, Leo Deng, K…...

复变函数中的对数函数及其MATLAB演示
复变函数中的对数函数及其MATLAB演示 引言 在实变函数中,对数函数 ln x \ln x lnx定义在正实数集上,是一个相对简单的概念。然而,当我们进入复变函数领域时,对数函数展现出更加丰富和复杂的性质。本文将介绍复变函数中对数函…...

【Linux】Linux程序地址基础
参考博客:https://blog.csdn.net/sjsjnsjnn/article/details/125533127 一、地址空间的阐述 1.1 程序地址空间 下面的图片展示了程序地址空间的组成结构 我们通过代码来验证一下 int g_unval; int g_val 100;int main(int argc, char *argv[]);void test1() {i…...
React 项目初始化与搭建指南
React 项目初始化有多种方式,可以选择已有的脚手架工具快速创建项目,也可以自定义项目结构并使用构建工具实现项目的构建打包流程。 1. 脚手架方案 1.1. Vite 通过 Vite 创建 React 项目非常简单,只需一行命令即可完成。Vite 的工程初始化…...

将图形可视化工具的 Python 脚本打包为 Windows 应用程序
前文我们已经写了一个基于python的tkinter库和matplotlib库的图形可视化工具。 基于Python的tkinter库的图形可视化工具(15种图形的完整代码):基于Python的tkinter库的图形可视化工具(15种图形的完整代码)-CSDN博客 在前文基础上&…...
AWS DocumentDB vs MongoDB:数据库的技术抉择
随着非关系型数据库在现代应用中的广泛应用,文档型数据库因其灵活的结构与出色的扩展性,逐渐成为企业开发与架构设计中的核心选择。在众多文档数据库中,MongoDB 凭借其成熟生态与社区支持占据主导地位;与此同时,AWS 提…...

无人机军用与民用技术对比分析
一、材料区别 军用无人机: 1. 高强度特种材料: 大量使用钛合金、碳纤维复合材料,兼顾轻量化与高强度,提升抗冲击性和隐身性能。 关键部件依赖进口材料。 2. 隐身涂层: 采用雷达吸波材料和低红外特征涂料…...

刷leetcode hot100--矩阵6/1
1.螺旋矩阵【很久】6/1【感觉就是思路的搬运工,没完全理解】 54. 螺旋矩阵 - 力扣(LeetCode) 原来想 但是如果是奇数矩阵,遍历不到中间 解决思路: 用left,right,top,down标记/限定每次遍历的元素,每次从…...
Qt 中实现文本截断(ellipsis)的功能。Qt 提供了此方法来处理过长的文本显示问题,例如在界面中限制文本长度并添加省略号(...)
QElidedText 并不是 Qt 中的标准类名或功能名称,但根据你的描述,你可能是指 QFontMetrics::elidedText() 方法。这是一个用于在 Qt 中实现文本截断(ellipsis)的功能。Qt 提供了此方法来处理过长的文本显示问题,例如在界…...
Cisco IOS XE WLC 任意文件上传漏洞复现(CVE-2025-20188)
免责申明: 本文所描述的漏洞及其复现步骤仅供网络安全研究与教育目的使用。任何人不得将本文提供的信息用于非法目的或未经授权的系统测试。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权,请及时与我们联系,我们将尽快处理并删除相关内容。 前…...
基于ResNet残差网络优化梯度下降算法实现图像分类
文章目录 题 目: 基于ResNet残差网络优化梯度下降算法实现图像分类基于ResNet残差神经网络优化梯度下降算法实现海贼王图像分类引言1.ResNet残差神经网络介绍1.1 ResNet残差神经网络的研究现状1.2 ResNet残差神经网络的原理1.3 ResNet残差神经网络的实现步骤1.3.1导入必要的库…...
群晖NAS套件历史版本资源
有时候需要下载历史的群晖套件,可以通过以下地址前往 Synology Archive Download Site - Index of /download 该页面汇集了各类群晖应用程序的过往版本,方便用户根据需要选择特定版本的软件进行下载安装。这种方式适用于需要旧版软件兼容性或进行版本回…...