RabbitMQ之死信队列、延迟队列和懒队列

目录

死信队列

何时会产生死信

死信队列的配置方式

参数x-dead-letter-routing-key

如何确定一个消息是不是死信

延迟队列

懒队列

声明懒队列的两种方式

参数声明

策略指定


死信队列

死信队列是RabbitMQ中非常重要的一个特性。简单理解,他是RabbitMQ对于未能正常消费的消息进行的一种补救机制。死信队列也是一个普通的队列,同样可以在队列上声明消费者,继续对消息进行消费处理。

​ 对于死信队列,在RabbitMQ中主要涉及到几个参数:

x-dead-letter-exchange指定一个交换机作为死信交换机,然后x-dead-letter-routing-key指定交换机的RoutingKey。而接下来,死信交换机就可以像普通交换机一样,通过RoutingKey将消息转发到对应的死信队列中。

何时会产生死信

以下三种情况,RabbitMQ会将一个正常消息转成死信

  1. 消息被消费者确认拒绝。消费者把requeue参数设置为true(false),并且在消费后,向RabbitMQ返回拒绝。channel.basicReject或者channel.basicNack。

  2. 消息达到预设的TTL时限还一直没有被消费。TTL即最长存活时间 Time-To-Live 。消息在队列中保存时间超过这个TTL,即会被认为死亡。如果配置了死信队列,死亡的消息会进入该队列。

设置TTL有两种方式,一是通过配置策略指定,另一种是给队列单独声明TTL。

策略配置方式: Web管理平台配置 或者 使用指令配置 30000为毫秒单位

复制代码
rabbitmqctl set_policy TTL ".*" '{"message-ttl":30000}' --apply-to queues

声明队列时指定:同样可以在Web管理平台配置,也可以在代码中配置

java 复制代码
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-message-ttl", 60000);
channel.queueDeclare("myqueue", false, false, false, args);
  1. 消息由于队列已经达到最长长度限制而被丢掉。

死信队列的配置方式

RabbitMQ中有两种方式可以声明死信队列,一种是针对某个单独队列指定对应的死信队列。另一种就是以策略的方式进行批量死信队列的配置。

针对多个队列,可以使用策略方式,配置统一的死信队列:

java 复制代码
rabbitmqctl set_policy DLX ".*" '{"dead-letter-exchange":"my-dlx"}' --apply-to queues

针对队列单独指定死信队列的方式主要是之前提到的三个属性:

java 复制代码
channel.exchangeDeclare("deadexchange", "direct");
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-dead-letter-exchange", "deadexchange");
channel.queueDeclare("myqueue", false, false, false, args);

这些参数,也可以在RabbitMQ的管理页面进行配置。例如配置策略时:

在对队列进行配置时,只有Classic经典队列和Quorum仲裁队列才能配置死信队列,而目前Stream流式队列,并不支持配置死信队列。


参数x-dead-letter-routing-key

当消息被投递到死信队列时,它会携带原始消息的routing key,除非配置了 x-dead-letter-routing-key 参数,此时会将routing key替换为指定的值。需要注意的是,这个过程是由 RabbitMQ 管理的,而不经过消息发送者的确认,因此在死信消息转移的过程中,无法由发送者确保消息的安全性。

如何确定一个消息是不是死信

消息被作为死信转移到死信队列后,会在Header当中增加一些消息。会加上第一次成为死信的三个属性,并且这三个属性在以后的传递过程中都不会更改。

javascript 复制代码
x-first-death-reason
x-first-death-queue
x-first-death-exchange

延迟队列

RabbitMQ中,是不存在延迟队列的功能的,而通常如果要用到延迟队列,就会采用TTL+死信队列的方式来处理。RabbitMQ提供了一个rabbitmq_delayed_message_exchange插件,可以实现延迟队列的功能,但是并没有集成到官方的发布包当中,需要单独去下载。

TTL+死信队列实现逻辑,创建一个普通交换机跟队列,给队列设置TTL超时时间,但是不给这个队列绑定消费者,给这个普通队列绑定死信交换机,等到消息超时就会发送到死信交换机,给死信交换机配一个消费者来消费。这种方式可以实现延迟队列的功能。但在一些情况下可能会有一些局限性,比如无法实现非常精确的延迟。

为了更方便、更灵活地实现延迟队列功能,可以使用RabbitMQ提供的插件rabbitmq_delayed_message_exchange,这个插件为RabbitMQ提供了原生的延迟队列支持,允许在不使用死信队列的情况下直接实现延迟消息的发送和消费。


懒队列

RabbitMQ从3.6.0版本开始,就引入了懒队列(Lazy Queue)的概念。懒队列会尽可能早的将消息内容保存到硬盘当中,并且只有在用户请求到时,才临时从硬盘加载到RAM内存当中。懒队列的设计目标是为了支持非常长的队列(数百万级别)。队列可能会因为一些原因变得非常长也就是数据堆积。比如消费者服务宕机了、有一个突然的消息高峰,生产者生产消息超过消费者、消费者消费太慢了,都有可能造成数据堆积。

默认情况下,RabbitMQ接收到消息时,会保存到内存以便使用,同时把消息写到硬盘。但是,消息写入硬盘的过程中,是会阻塞队列的。RabbitMQ虽然针对写入硬盘速度做了很多算法优化,但是在长队列中,依然表现不是很理想,所以就有了懒队列的出现。​ 懒队列会尝试尽可能早的把消息写到硬盘中。这意味着在正常操作的大多数情况下,RAM(内存)中要保存的消息要少得多(数据都在硬盘中)。

声明懒队列的两种方式

参数声明

在代码中可以通过x-queue-mode参数指定

java 复制代码
  Map<String, Object> args = new HashMap<String, Object>();
  args.put("x-queue-mode", "lazy");
  channel.queueDeclare("myqueue", false, false, false, args);
策略指定
java 复制代码
rabbitmqctl set_policy Lazy "^lazy-queue$" '{"queue-mode":"default"}' --apply-to queues

当一个队列被声明为懒队列,那即使队列被设定为不持久化,消息依然会写入到硬盘中。如果是在集群模式中使用,会给集群资源带来很大的负担。

懒队列适合消息量大且长期有堆积的队列,可以减少内存使用,加快消费速度。但是这是以大量消耗集群的网络及磁盘IO为代价的

相关推荐
Victor3561 分钟前
Redis(111)Redis的持久化机制有哪些?
后端
Victor3563 分钟前
Redis(110)Redis的发布订阅机制如何使用?
后端
Acrelhuang18 分钟前
小小电能表,如何撬动家庭能源革命?
java·大数据·开发语言·人工智能·物联网
jyd012424 分钟前
MongoDB 与 Java 实体类型 LocalTime 时区转换问题解决方案
java·数据库·mongodb
Python私教30 分钟前
使用 FastAPI 实现文件上传接口:从入门到进阶
后端
一抓掉一大把1 小时前
RuoYI框架.net版本实现Redis数据隔离
java·开发语言
一抓掉一大把1 小时前
RuoYi .net-实现商城秒杀下单(redis,rabbitmq)
redis·mysql·c#·rabbitmq·.net
.格子衫.1 小时前
Maven高级
java·maven
lkbhua莱克瓦241 小时前
Java基础——常用算法4
java·数据结构·笔记·算法·github·排序算法·快速排序
.格子衫.1 小时前
Maven前奏
java·pycharm·maven