RabbitMQ--延迟队列

(一)延迟队列

1.概念

 延迟队列是一种特殊的队列,消息被发送后,消费者并不会立刻拿到消息,而是等待一段时间后,消费者才可以从这个队列中拿到消息进行消费

2.应用场景

 延迟队列的应用场景很多,就比如大部分定时的场景,我们都可以利用延迟队列例如:闹钟定时,预约会议,空调定时开关等

 但是RabbitMQ是没有直接给我们提供延迟队列的,但是我们可以通过上一篇博客说的ttl和死信来达到延迟队列的效果,具体操作如下

 首先我们有一个交换机和一个队列,然后此队列又指定一个死信交换机,死信交换机绑定一个死信队列,然后我们消费者并不是从正常队列中获取消息,而是从死信队列中获取消息,通过给消息/队列设置过期时间来影响消息到达死信队列的时间,消费者拿到消息就会延迟,这样就可以模拟出延迟的效果。

那接下来就是我们的代码实现

首先我们通过设置队列ttl来实现

 @Bean("ttlExchange")public Exchange ttlExchange(){return ExchangeBuilder.directExchange(Constants.TTL_EXCHANGE).durable(true).build();}@Bean("ttlQueue")public Queue ttlQueue(){return QueueBuilder.durable(Constants.TTL_QUEUE).ttl(5000).deadLetterExchange(Constants.DEAD_EXCHANGE).deadLetterRoutingKey("dead").build();}@Bean("ttlBind")public Binding ttlBind(@Qualifier("ttlExchange") Exchange ackExchange,@Qualifier("ttlQueue") Queue queue){return BindingBuilder.bind(queue).to(ackExchange).with("ttl").noargs();}@Bean("deadExchange")public Exchange deadExchange(){return ExchangeBuilder.directExchange(Constants.DEAD_EXCHANGE).durable(true).build();}@Bean("deadQueue")public Queue deadQueue(){return QueueBuilder.durable(Constants.DEAD_QUEUE).build();}@Bean("deadBind")public Binding deadBind(@Qualifier("deadExchange") Exchange ackExchange,@Qualifier("deadQueue") Queue queue){return BindingBuilder.bind(queue).to(ackExchange).with("dead").noargs();}

然后生产者代码没什么变化

 @RequestMapping("ttl")public String TTLPro(){String s1="ttl test";Message message=new Message(s1.getBytes(StandardCharsets.UTF_8));
//        message.getMessageProperties().setExpiration("10000");RabbitTemplate.convertAndSend(Constants.TTL_EXCHANGE,"ttl",message);return "发送成功";}

只不过消费者订阅的是死信队列

@RabbitListener(queues = Constants.DEAD_QUEUE)public void ListenerQueue2(Message message,Channel channel) throws IOException {long Tag=message.getMessageProperties().getDeliveryTag();try {System.out.println("接收到消息: "+ new String(message.getBody())+" TagID: "+Tag);int num=3/0;     //模拟失败channel.basicAck(Tag,false);System.out.println("处理完成");}catch (Exception e){channel.basicReject(Tag,false);}}

这样过了5s后我们就可以从死信队列中获取到延迟消息了

那我们再来通过设置消息的ttl来看一下

首先我们要把队列的ttl给取消掉,记得要删队列

 @Bean("ttlExchange")public Exchange ttlExchange(){return ExchangeBuilder.directExchange(Constants.TTL_EXCHANGE).durable(true).build();}@Bean("ttlQueue")public Queue ttlQueue(){return QueueBuilder.durable(Constants.TTL_QUEUE).deadLetterExchange(Constants.DEAD_EXCHANGE).deadLetterRoutingKey("dead").build();}@Bean("ttlBind")public Binding ttlBind(@Qualifier("ttlExchange") Exchange ackExchange,@Qualifier("ttlQueue") Queue queue){return BindingBuilder.bind(queue).to(ackExchange).with("ttl").noargs();}@Bean("deadExchange")public Exchange deadExchange(){return ExchangeBuilder.directExchange(Constants.DEAD_EXCHANGE).durable(true).build();}@Bean("deadQueue")public Queue deadQueue(){return QueueBuilder.durable(Constants.DEAD_QUEUE).build();}@Bean("deadBind")public Binding deadBind(@Qualifier("deadExchange") Exchange ackExchange,@Qualifier("deadQueue") Queue queue){return BindingBuilder.bind(queue).to(ackExchange).with("dead").noargs();}

  然后我们发送一个ttl时间为10s的,再发送一个5s的,我们知道这样两条数据是会发生错误的,因为我们设置消息过期时间,我们RabbitMQ(性能问题)并不会遍历整个消息队列看看谁过没过期,如果过期的消息不在队头,那么只有当使用的时候,才会真正的进行一些过期处理,比如传给死信交换机 

@RequestMapping("ttl")public String TTLPro(){String s1="ttl test";Message message=new Message(s1.getBytes(StandardCharsets.UTF_8));message.getMessageProperties().setExpiration("10000");RabbitTemplate.convertAndSend(Constants.TTL_EXCHANGE,"ttl",message);message.getMessageProperties().setExpiration("5000");RabbitTemplate.convertAndSend(Constants.TTL_EXCHANGE,"ttl",message);return "发送成功";}

如果正常,会在5s后接收到第一个消息,在10s后接收到第二个消息,但是此时我们会同一时间(10s)接收到两条消息

  那这个问题在上一篇ttl的时候就说过了,这里依然是个问题,虽然设置队列的ttl不会有这个问题,但是设置队列ttl我们针对不同延迟时间就需要创建多个队列,这是不太合理的,所以针对这个问题,我们有一个延迟队列的插件可以使用

 3.延迟队列插件

延迟队列插件,会给我们提供一个特殊的交换机,来完成我们的延迟功能

这是我们插件的下载地址

https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases

  我们需要找到ez文件并下载,但是注意这里的版本要与你的RabbitMQ版本可以匹配,否则之后会出现问题

那插件下完后,我们要找到对应目录,下载插件

上面两个目录,我们可以任选一个下载即可,没有这个目录,我们手动创建

然后把下载的ez文件,copy到这个目录中即可,然后我们可以使用命令 rabbitmq-plugins list 来查看插件列表,看看我们有没有成功放进去,但是注意,即使我们成功放进去并成功显示了,也可能会出错,这就可能是你们下载的RabbitMQ版本与整个延迟插件的版本不匹配,重新下载其他版本即可

然后我们启动插件rabbitmq-plugins enable rabbitmq_delayed_message_exchange

之后重启服务service rabbitmq-server restart

在没有发生错误的情况下,我们就发现我们会多了一个默认的交换机

此时我们代码中就不需要声明普通交换机了而是直接使用默认交换机即可

我们生产者代码是需要改一下的,我们需要调用一个方法来设置延迟时间

@RequestMapping("/delay2")
public String delay2() {//发送带ttl的消息 rabbitTemplate.convertAndSend(Constant.DELAYED_EXCHANGE_NAME, "delayed", 
"delayed test 20s..."+new Date(), messagePostProcessor -> {messagePostProcessor.getMessageProperties().setDelayLong(20000L); return messagePostProcessor;});rabbitTemplate.convertAndSend(Constant.DELAYED_EXCHANGE_NAME, "delayed", 
"delayed test 10s..."+new Date(), messagePostProcessor -> {messagePostProcessor.getMessageProperties().setDelayLong(10000L); //设置延迟时间 return messagePostProcessor;});return "发送成功!";
}

此时我们就可以在10s正确接收一个消息,在20s正确接收另一个消息 

  注意我们使用TTL+死信时消息传递给交换机后映射之后一直在正常队列中的,等待TTL时间到了把消息给死信交换机再映射到死信队列再拿到消息,我们使用插件的时候,消息是在RabbitMQ给我们提供的那个特殊的交换机中的,等待时间到了,再映射给队列,然后从队列中拿消息

4.常见面试题

介绍下延迟队列

我们可以这样回答:

 延迟队列是一个特殊的队列,消息发送后,消费者并不会立刻拿到,而是等待一定延迟时间后才发送给消费者进行消费

 并且延迟队列的应用场景很多,比如订单支付,智能家电,以及定时邮箱

 但是延迟队列在RabbitMQ中并没有直接给我们提供,我们可以通过TTL+死信的方式或者使用延迟插件的方式来实现延迟功能

 两者的区别:

1.通过TTL+死信

 优点:比较灵活,不需要我们额外引入插件

 缺点:我们设置消息TTL的时候可能会出现顺序的问题,而且我们需要多创建死信队列和死信交换机,完成一些绑定,增加了系统的复杂性

2.基于插件实现的延迟队列

 优点:通过插件能够简化延迟消息的实现,并且避免了时序问题

 缺点:需要依赖插件,不同版本RabbitMQ需要不同版本插件,有运维工作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/4031.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

口令攻击和钓鱼攻击

口令攻击和钓鱼攻击 1、实验说明 口令攻击和钓鱼攻击是生活中两种较为常见的攻击方式, 通过对攻击过程的复现, 能够让学生对其有直观的认识, 进而思考相应的防范措施。 2、实验目的 (1 )能够了解实验规范和实验所需…

考前64天 学习笔记 - 形成“习惯体系”进行最小启动

从2025年1月18日到3月22日还剩64天 一、备考心态 这几天摆烂,并没有怎么学,败在了游戏和短视频上。 每分每秒都在抵御其他诱惑 科学表明:人在做自己不喜欢的事情,意志力最多能挺25分钟 如何稳定自己的心态,答案就在…

【python_钉钉群发图片】

需求: **在钉钉群发图片,需要以图片的形式展示,如图所示:**但是目前影刀里面没有符合条件的指令 解决方法: 1、在钉钉开发者后台新建一个自建应用,发版,然后获取里面的appkey和appsecret&am…

R数据分析:有调节的中介与有中介的调节的整体介绍

单独的有调节的中介或者有中介的调节好多同学还大概能看明白,但是两个东西一起说我发现大部分同学就懵逼了。今天我就尝试将两种方法一起讲讲,重点帮助大家厘清两种方法的异同。 先从整体上看下两者的概念: 有中介的调节首先落脚在调节,调节作用必须是显著的,并且这个调…

DETR论文阅读

1. 动机 传统的目标检测任务需要大量的人工先验知识,例如预定义的先验anchor,NMS后处理策略等。这些人工先验知识引入了很多人为因素,且较难处理。如果能够端到端到直接生成目标检测结果,将会使问题变得很优雅。 2. 主要贡献 提…

天机学堂5-XxlJobRedis

文章目录 梳理前面的实现:Feign点赞改进 day07-积分系统bitmap相关命令签到增加签到记录计算本月已连续签到的天数查询签到记录 积分表设计签到-->发送RabbitMQ消息,保存积分对应的消费者:**消费消息 用于保存积分**增加积分查询个人今日积…

万字长文介绍ARINC 653,以及在综合模块化航空电子设备(IMA)中的作用

文章目录 一、引言二、ARINC 653背景三、整体系统架构四、应用/执行(APEX)接口五、ARINC 653 RTOS内部机制六、健康监测功能七、软件应用八、ARINC 653现状九、总结 一、引言 在现代航空领域,综合模块化航空电子设备(IMA&#xf…

认识 MySQL 和 Redis 的数据一致性问题

参考:https://zhuanlan.zhihu.com/p/429637485 1. 什么是数据的一致性 “数据一致”一般指的是:缓存中有数据,缓存的数据值 数据库中的值。 但根据缓存中是有数据为依据,则”一致“可以包含两种情况: 缓存中有数据…

【论文笔记】SmileSplat:稀疏视角+pose-free+泛化

还是一篇基于dust3r的稀疏视角重建工作,作者联合优化了相机内外参与GS模型,实验结果表明优于noposplat。 abstract 在本文中,提出了一种新颖的可泛化高斯方法 SmileSplat,可以对无约束(未标定相机的)稀疏多…

创建 pdf 合同模板

创建 pdf 合同模板 一、前言二、模板展示三、制作过程 一、前言 前段时间要求创建“pdf”模板,学会了后感觉虽然简单,但开始也折腾了好久,这里做个记录。 二、模板展示 要创建这样的模板 三、制作过程 新建一个“Word”,这里命…

电力场景红外测温图像绝缘套管分割数据集labelme格式2436张1类别

数据集格式:labelme格式(不包含mask文件,仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数):2436 标注数量(json文件个数):2436 标注类别数:1 标注类别名称:["arrester"] 每个类别标注的框数&am…

【网络协议】RFC3164-The BSD syslog Protocol

引言 Syslog常被称为系统日志或系统记录,是一种标准化的协议,用于网络设备、服务器和应用程序向中央Syslog服务器发送日志消息。互联网工程任务组(IETF)发布的RFC 3164,专门定义了BSD Syslog协议的规范和实现方式。通…

正态分布检验(JB检验和威尔克检验)和斯皮尔曼相关系数(继上回)

正态分布的检验 1,JB检验(n>30) (1)偏度和峰度 描述函数正不正,高不高的 Matlab中计算偏度和峰度的函数是:skewness() 和 kurtosis() 我们以normrnd来生成一个100*1的均值为2,标准差为3的正态分布(这里采用的第一个公式) 得到下面的数据,因为这个…

搭建一个基于Spring Boot的书籍学习平台

搭建一个基于Spring Boot的书籍学习平台可以涵盖多个功能模块,例如用户管理、书籍管理、学习进度跟踪、笔记管理、评论和评分等。以下是一个简化的步骤指南,帮助你快速搭建一个基础的书籍学习平台。 — 1. 项目初始化 使用 Spring Initializr 生成一个…

基于Python的心电图报告解析与心电吸引子绘制

一、引言 1.1 研究背景与意义 心脏作为人体的核心器官,其正常电活动对于维持生命活动至关重要。心电图(Electrocardiogram,ECG)作为记录心脏电活动随时间变化的重要工具,能够直观反映心脏的节律、传导等功能状态&…

【大数据】机器学习------支持向量机(SVM)

支持向量机的基本概念和数学公式: 1. 线性可分的支持向量机 对于线性可分的数据集 ,其中(x_i \in R^d) 是特征向量 是类别标签,目标是找到一个超平面 ,使得对于所有 的样本 ,对于所有(y_i -1) 的样本,…

左神算法基础提升--4

文章目录 树形dp问题Morris遍历 树形dp问题 求解这个问题需要用到我们在基础班上学到的从节点的左子树和右子树上拿信息的方法。 求最大距离主要分为两种情况:1.当前节点参与最大距离的求解;2.当前节点不参与最大距离的求解; 1.当前节点参与最…

53,【3】BUUCTF WEB october 2019 Twice SQLinjection

题目得到信息,2次注入,进入靶场 登录页面,很自然想到SQL 第一次注入应该是这个可以登录,注册,提交简介的页面 第二次注入应该是在info处注入,信息显示在简介处 我真的纯脑子有病,人家二次注入不…

python编程-OpenCV(图像读写-图像处理-图像滤波-角点检测-边缘检测)图像变换

形态变换 图像处理中的形态学操作是处理图像结构的有效方法。以下是一些常见的形态学操作的介绍及其在 OpenCV 中的实现示例。 1. 腐蚀(Erosion) 腐蚀操作通过消除图像边界来减少图像中的白色区域(前景),使物体的边…

Spring Boot + Apache POI 实现 Excel 导出:BOM物料清单生成器(支持中文文件名、样式美化、数据合并)

目录 引言 Apache POI操作Excel的实用技巧 1.合并单元格操作 2.设置单元格样式 1. 创建样式对象 2. 设置边框 3. 设置底色 4. 设置对齐方式 5. 设置字体样式 6.设置自动换行 7. 应用样式到单元格 3. 定位和操作指定单元格 4.实现标签-值的形式 5.列宽设置 1. 设…