Spring RabbitMQ那些事(2-两种方式实现延时消息订阅)
目录
- 一、序言
- 二、死信交换机和消息TTL实现延迟消息
- 1、死信队列介绍
- 2、代码示例
- (1) 死信交换机配置
- (2) 消息生产者
- (3) 消息消费者
- 3、测试用例
- 三、延迟消息交换机实现延迟消息
- 1、安装延时消息插件
- 2、代码示例
- (1) 延时消息交换机配置
- (2) 消息生产者
- (3) 消息消费者
- 3、测试用例
- 四、两种实现方式优缺点
- 1、延时消息插件
- 2、TLL&死信交换机
一、序言
业务开发中有很多延时操作的场景,比如最常见的超时订单自动关闭、延时异步处理,我们常用的实现方式有:
- 定时任务轮询(有延时)。
- 借助Redission的延时队列。
- Redis的key过期事件通知机制(需开启key过期事件通知,对Redis有性能损耗)。
- RocketMQ中定时消息推送(支持的时间间隔固定,不支持自定义)。
- RabbitMQ中的死信队列和延迟消息交换机。
其中用的最多的也是借助Redisson实现的数据结构延迟队列和RabbitMQ中的死信队列来实现,今天我们通过RabbitMQ死信队列和延迟消息交换机(新特性)来实现延时消息推送。
二、死信交换机和消息TTL实现延迟消息
1、死信队列介绍
这种方式主要通过结合消息过期和私信交换机来实现延迟消息推送,首先先了解下哪些消息会进入死信队列:
- 被消费者
nack(negatively acknowleged)的消息。 TTL过期后未被消费的消息。- 超过队列长度限制后被丢弃的消息。
备注:更多信息请参考RabbitMQ中的 Dead Letter Exchange。
2、代码示例
(1) 死信交换机配置
@Configuration
protected static class DeadLetterExchangeConfig {@Beanpublic Queue deadLetterQueue(){return QueueBuilder.durable("dead-letter-queue").build();}@Beanpublic DirectExchange deadLetterExchange() {return ExchangeBuilder.directExchange("dead-letter-exchange").build();}@Beanpublic Binding bindQueueToDeadLetterExchange(Queue deadLetterQueue, DirectExchange deadLetterExchange) {return BindingBuilder.bind(deadLetterQueue).to(deadLetterExchange).with("dead-letter-routing-key");}@Beanpublic Queue normalQueue() {return QueueBuilder.durable("normal-queue").deadLetterExchange("dead-letter-exchange").deadLetterRoutingKey("dead-letter-routing-key").build();}}
(2) 消息生产者
@Slf4j
@Component
@RequiredArgsConstructor
public class RabbitMqProducer {private final RabbitTemplate rabbitTemplate;public void sendMsgToDeadLetterExchange(String body, int timeoutInMillSeconds) {log.info("开始发送消息到dead letter exchange 消息体:{}, 消息延迟:{}ms, 当前时间:{}", body, timeoutInMillSeconds, LocalDateTime.now());MessageProperties messageProperties = MessagePropertiesBuilder.newInstance().setExpiration(String.valueOf(timeoutInMillSeconds)).build();Message message = MessageBuilder.withBody(body.getBytes(StandardCharsets.UTF_8)).andProperties(messageProperties).build();rabbitTemplate.send("normal-queue", message);}}
(3) 消息消费者
@Slf4j
@Component
public class RabbitMqConsumer {@RabbitListener(queues = "dead-letter-queue")public void handleMsgFromDeadLetterQueue(String msg) {log.info("Message received from dead-letter-queue, message body: {}, current time:{}", msg, LocalDateTime.now());}
}
3、测试用例
@RestController
@RequiredArgsConstructor
public class RabbitMsgController {private final RabbitMqProducer rabbitMqProducer;@RequestMapping("/exchange/dead-letter")public ResponseEntity<String> sendMsgToDeadLetterExchange(String body, int timeout) {rabbitMqProducer.sendMsgToDeadLetterExchange(body, timeout);return ResponseEntity.ok("消息发送到死信交换机成功");}}
浏览器访问http://localhost:8080/exchange/dead-letter?body=hello&timeout=5000,可以看到消息被延迟5s处理。
2023-11-26 11:50:33.041 INFO 19152 --- [nio-8080-exec-7] c.u.r.i.producer.RabbitMqProducer : 开始发送消息到dead letter exchange 消息体:hello, 消息延迟:5000ms, 当前时间:2023-11-26T11:50:33.041
2023-11-26 11:50:38.054 INFO 19152 --- [ntContainer#4-4] c.u.r.i.consumer.RabbitMqConsumer : Message received from dead-letter-queue, message body: hello, current time:2023-11-26T11:50:38.054
三、延迟消息交换机实现延迟消息
上面通过消息TTL和死信交换机实现延迟消息的解决方案是由一个叫James Carr的人提出来的,后来RabbitMQ提供了一个开箱即用的解决方案,通过延时消息插件来实现。
该插件以前被当做是试验性产品,但是现在已经可以投产使用了。(PS:2015年4月16号就已经有该插件文档)
在Spring AMQP中,同样提供了对该延时消息插件的支持,并且在RabbitMQ 3.6.0版本就已经测试通过。
1、安装延时消息插件
该延时消息插件为社区插件,因此需要自己手动下载安装的RabbMQ版本对应的插件,下载地址:RabbitMQ延时消息插件releases。
我安装的RabbitMQ版本为3.9.9,3.9.0版本的插件对所有3.9.x版本的RabbitMQ都支持。

下载完后把.ez结尾的插件复制RabbitMQ的插件目录下,插件目录为/usr/lib/rabbitmq/plugins 。

通过命令rabbitmq-plugins enable rabbitmq_delayed_message_exchange安装该插件,通过命令rabbitmq-plugins list查看插件列表,可以看到该延时消息插件已经成功安装。

2、代码示例
(1) 延时消息交换机配置
@Configuration
protected static class DelayedMsgExchangePluginConfig {@Beanpublic Queue delayedQueue() {return QueueBuilder.durable("delayed-queue").build();}@Beanpublic DirectExchange delayedExchange() {return ExchangeBuilder.directExchange("delayed-exchange").delayed().build();}@Beanpublic Binding bindDelayedQueueToDelayedChange(Queue delayedQueue, DirectExchange delayedExchange) {return BindingBuilder.bind(delayedQueue).to(delayedExchange).with("delayed-routing-key");}
}
备注:延时交换机的类型可以为DirectExchage、TopicExcahge和FanoutExchange,这些都支持。
(2) 消息生产者
@Slf4j
@Component
@RequiredArgsConstructor
public class RabbitMqProducer {private final RabbitTemplate rabbitTemplate;public void sendDelayedMsg(String body, int timeoutInMillSeconds) {log.info("开始发送消息到delayed-exchange 消息体:{}, 消息延迟:{}ms, 当前时间:{}", body, timeoutInMillSeconds, LocalDateTime.now());MessageProperties messageProperties = new MessageProperties();messageProperties.setDelay(timeoutInMillSeconds);Message message = MessageBuilder.withBody(body.getBytes(StandardCharsets.UTF_8)).andProperties(messageProperties).build();rabbitTemplate.send("delayed-exchange", "delayed-routing-key", message);}
}
(3) 消息消费者
@Slf4j
@Component
public class RabbitMqConsumer {@RabbitListener(queues = "delayed-queue")public void handleMsgFromDelayedQueue(String msg) {log.info("Message received from delayed-queue, message body: {}, current time:{}", msg, LocalDateTime.now());}
}
3、测试用例
@RestController
@RequiredArgsConstructor
public class RabbitMsgController {private final RabbitMqProducer rabbitMqProducer;@RequestMapping("/exchange/delayed")public ResponseEntity<String> sendMsgToHeadersExchange(String body, int timeout) {rabbitMqProducer.sendDelayedMsg(body, timeout);return ResponseEntity.ok("消息发送到延迟交换机成功");}}
浏览器访问http://localhost:8080/exchange/dead-letter?body=hello&timeout=5000,可以看到消息被延迟5s处理。
2023-11-26 13:02:07.816 INFO 26524 --- [nio-8080-exec-3] c.u.r.i.producer.RabbitMqProducer : 开始发送消息到delayed-exchange 消息体:Hello, 消息延迟:5000ms, 当前时间:2023-11-26T13:02:07.816
2023-11-26 13:02:12.830 INFO 26524 --- [ntContainer#5-5] c.u.r.i.consumer.RabbitMqConsumer : Message received from delayed-queue, message body: Hello, current time:2023-11-26T13:02:12.829
四、两种实现方式优缺点
1、延时消息插件
- 优点:配置更加简单,少配置1个队列,且语义更明确,容易定位消息出入口。
- 缺点:延时消息插件对RabbitMQ版本有要求,延时消息交换机
2、TLL&死信交换机
- 优点:基本适用于所有RabbitMQ版本。
- 缺点:配置相对来说复杂一些,还有就是我们最开始提到的,不只是TTL过期的消息才会进入死信队列,还有
超出队列限制和nack的消息也会进入死信队列,触发的条件没那么纯粹。

相关文章:
Spring RabbitMQ那些事(2-两种方式实现延时消息订阅)
目录 一、序言二、死信交换机和消息TTL实现延迟消息1、死信队列介绍2、代码示例(1) 死信交换机配置(2) 消息生产者(3) 消息消费者 3、测试用例 三、延迟消息交换机实现延迟消息1、安装延时消息插件2、代码示例(1) 延时消息交换机配置(2) 消息生产者(3) 消息消费者 3、测试用例 …...
免费SSL证书有效期只有90天?太短?
随着网络安全问题日益受到重视,SSL证书成为了网站安全的必需品。然而,在许多情况下,免费提供的SSL证书往往只有90天的有效期,这种期限对于很多用户来说显得过于短暂。 首先,我们要理解为什么 SSL 证书的有效期设定为90…...
Java小游戏 王者荣耀
GameFrame类 所需图片: package 王者荣耀;import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.File; import java.util.ArrayLis…...
Python:diskcache实现基于文件的数据缓存
diskcache是一个基于Sqlite文件的数据缓存 文档 https://grantjenks.com/docs/diskcache/https://github.com/grantjenks/python-diskcachehttps://pypi.org/project/diskcache/ 示例 from diskcache import Cache# 指定文件夹 cache Cache(./cache)# 存 cache.set(name, …...
微信小程序 - 一篇带你解读小程序强制更新(冷/热启动)
在小程序开发中,我们会不可避免的涉及到小程序新版本迭代的问题,因为小程序的更新机制是异步的,新版本发布后并不会立刻应用到所有的现有用户,部分用户用的可能还是原来的旧版本,但如果是急需修复的 bug 或其他急需上线…...
关于接口测试自动化的总结与思考!
序 近期看到阿里云性能测试 PTS 接口测试开启免费公测,本着以和大家交流如何实现高效的接口测试为出发点,本文包含了我在接口测试领域的一些方法和心得,希望大家一起讨论和分享,内容包括但不仅限于: 服务端接口测试介…...
如何用低代码的思路设计文字描边渐变组件
前言 文字特效设计一直是困扰 Web 前端 Css 世界多年的问题, 比如如何用纯 Css 实现文字描边, 渐变, 阴影等, 由于受限于浏览器兼容性的问题, 我们不得不使用其他替代方案来实现. 平时工作中我们使用 PS 等设计工具能很容易的实现文字渐变等特效, 但是随着可视化技术的成熟, 我…...
Linux 网络通信
(一)套接字Socket概念 Socket 中文意思是“插座”,在 Linux 环境下,用于表示进程 x 间网络通信的特殊文件 类型。本质为内核借助缓冲区形成的伪文件。 既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。Linux 系统…...
借力互联网,民营医院探索互联网医疗服务的发展方向
民营医院互联网医疗服务是指利用互联网技术和平台,为患者提供更加便捷、高效的医疗服务。在当前数字化时代,互联网医疗服务正逐渐成为医疗行业的新趋势,也为民营医院开拓了更广阔的发展空间。下面将围绕这一主题进行讨论: 首先&a…...
office tool plus工具破解word、visio等软件步骤
第一步:下载工具 破解需要用到office tool plus软件 office tool plus软件下载地址:Office Tool Plus 官方网站 - 一键部署 Office 选择其中一个下载到本地(本人选择的是第一个的云图小镇下载方式) 第二步:启动工具 …...
python之pyqt专栏5-信号与槽1
在上一篇文章,我们了解到如果想要用代码改变QLabel的文本内容,可以调用QLabel类的text()函数。 但是现在有个这样的需求,界面中有一个Button与一个Label,当点击Button时,将Label的内容改变为“Hello world!…...
【JMeter】不同场景下的接口请求
场景1: 上传文件接口即Content-Type=multipart/form-data 步骤: 1. 接口url,method以及path正常填写 2.文件上传content-type是multipart/form-data,所以可以勾选【use multipart/form-data】,如果还有其他请求头信息可以添加一个请求头元件 3.请求参…...
十八数字文化受邀参加版博会“区块链+版权”创新应用试点研讨会
2023年11月23日至25日,以“版权新时代 赋能新发展”为主题的第九届中国国际版权博览会在成都市中国西部国际博览城和天府国际会议中心举办。版博会是我国版权领域唯一的综合性、国际性、国家级版权专业博览会,本届版博会由国家版权局主办,四川…...
Centos 7 离线安装(tar) NodeJS 16 和 Vue
目录 一、下载Nodejs二、安装Nodejs2.1、创建安装目录2.2、上传安装包(无网络) or 直接下载(有网络)2.3、解压缩2.4、配置环境变量2.5、创建软连接2.6、更换镜像源2.7、验证是否安装成功 三、安装Vue四、卸载Nodejs 一、下载Nodejs Nodejs:https://nodejs.org/en/ …...
卸载软件最最最彻底的工具——Uninstall Tool
卸载软件最最最彻底的工具——Uninstall Tool Uninstall Tool 是一款功能强大的专业卸载工具。针对一些普通卸载不彻底的问题,它可以做到最优,比如Matlab等软件的卸载难的问题也可以较好地解决。 它比 Windows 自带的“添加/删除程序”功能快 3 倍&…...
2022年MathorCup大数据竞赛B题北京移动用户体验影响因素研究求解全过程文档及程序
2022年MathorCup高校数学建模挑战赛—大数据竞赛 B题 北京移动用户体验影响因素研究 原题再现: 移动通信技术飞速发展,给人们带来了极大便利,人们也越来越离不开移动通信技术带来的各种便捷。随着网络不断的建设,网络覆盖越来越…...
C#,《小白学程序》第二十课:大数的加法(BigInteger Add)
大数的(加减乘除)四则运算、阶乘运算。 乘法计算包括小学生算法、Karatsuba和Toom-Cook3算法。 重复了部分 19 课的代码。 1 文本格式 using System; using System.Linq; using System.Text; using System.Collections.Generic; /// <summary>…...
通用功能——git 攻略
摘要 本文主要介绍git常用命令的使用方法,同时介绍一些常见问题的处理方法,持续更新中… git命令通用选项 大多数git命令都适用的选项列表如下: -v, --verbose show hash and subject, give twice for upstream branch -q, --quie…...
LemMinX-Maven:帮助在eclipse中更方便地编辑maven的pom文件
LemMinX-Maven:https://github.com/eclipse/lemminx-maven LemMinX-Maven可以帮助我们在eclipse中更方便地编辑maven工程的pom.xml文件,例如补全、提示等。不用单独安装,因为在安装maven eclipse插件的时候已经自动安装了: 例…...
CAD与 PDM系统如何协同工作的?
在产品研发中,CAD(计算机辅助设计)和PDM(产品数据管理)是两个核心的工具,它们在产品从设计到制造的整个生命周期中发挥着重要的作用。虽然这两个工具在功能上有所不同,但它们在使用上却有着密切…...
Cursor无限制使用解决方案:cursor-free-vip完全指南
Cursor无限制使用解决方案:cursor-free-vip完全指南 【免费下载链接】cursor-free-vip [Support 0.45](Multi Language 多语言)自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro 功能: Youve reached your trial…...
OneDrive深度卸载与系统优化指南
OneDrive深度卸载与系统优化指南 【免费下载链接】OneDrive-Uninstaller Batch script to completely uninstall OneDrive in Windows 10 项目地址: https://gitcode.com/gh_mirrors/on/OneDrive-Uninstaller 一、问题引入:OneDrive在系统中的隐性影响 在现…...
一站式机器学习环境配置:从操作系统到运行NLP-StructBERT
一站式机器学习环境配置:从操作系统到运行NLP-StructBERT 刚接触AI开发,是不是感觉第一步就卡住了?看着网上各种教程,又是装系统,又是配环境,还要搞什么CUDA驱动,头都大了。别担心,…...
D3KeyHelper完全指南:从入门到精通的暗黑3技能自动化解决方案
D3KeyHelper完全指南:从入门到精通的暗黑3技能自动化解决方案 【免费下载链接】D3keyHelper D3KeyHelper是一个有图形界面,可自定义配置的暗黑3鼠标宏工具。 项目地址: https://gitcode.com/gh_mirrors/d3/D3keyHelper D3KeyHelper是一款专为暗黑…...
一个简单到尴尬却有效的SFT实验
卷友们好,我是rumor。上周Apple有篇论文做了一个简单到有点尴尬的实验:从模型自己采样一批代码答案,不过滤对错,不执行验证,直接拿去SFT。结果Qwen3-30B在LiveCodeBench v6上,pass1从42.4%涨到55.3%&#x…...
FLUX.1-dev像素生成器参数详解:如何通过Scale控制LoRA模组强度
FLUX.1-dev像素生成器参数详解:如何通过Scale控制LoRA模组强度 1. 认识像素幻梦的LoRA模组系统 像素幻梦(Pixel Dream Workshop)作为基于FLUX.1-dev的像素艺术生成终端,其核心优势在于灵活的LoRA模组系统。LoRA(Low-Rank Adaptation)技术允许我们在不改…...
自举电容在Buck电路中的关键作用-3个核心要点解析
1. 自举电容在Buck电路中的核心作用 我第一次接触Buck电路时,看到SW引脚旁边那个小小的电容,心里直犯嘀咕:这么个小东西能有多大作用?后来在实际项目中踩过几次坑才明白,这颗看似不起眼的自举电容(Cboot),其…...
SpringCloud微服务实战:从Eureka单机到集群,手把手教你搭建高可用注册中心(附避坑指南)
SpringCloud微服务实战:从Eureka单机到集群,手把手教你搭建高可用注册中心(附避坑指南) 微服务架构已经成为现代后端开发的标配,而服务注册中心则是微服务体系的"中枢神经系统"。作为SpringCloud生态的核心组…...
vLLM-v0.11.0完整指南:从环境搭建到Qwen3-VL-4B服务调用全流程
vLLM-v0.11.0完整指南:从环境搭建到Qwen3-VL-4B服务调用全流程 1. 环境准备与快速部署 1.1 硬件与系统要求 要运行vLLM-v0.11.0并部署Qwen3-VL-4B模型,建议满足以下硬件配置: 显卡:NVIDIA GPU(推荐RTX 4060 Ti 16G…...
RVC效果对比评测:vs So-VITS-SVC、DiffSinger、VITS2
RVC效果对比评测:vs So-VITS-SVC、DiffSinger、VITS2 1. 引言:为什么需要语音转换模型? 你有没有想过,用自己的声音唱出偶像的歌是什么感觉?或者,为你的视频角色配上另一个人的声音?这就是语音…...
