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(产品数据管理)是两个核心的工具,它们在产品从设计到制造的整个生命周期中发挥着重要的作用。虽然这两个工具在功能上有所不同,但它们在使用上却有着密切…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
