RabbitMQ的Queue详解;

一、前言

Queue(队列)是RabbitMQ的内部对象,用于存储消息队列,并将它们转发给消费者;

二、Queue队列

队列跟交换机共享某些属性,但是队列也有一些另外的属性

  • Name:队列的名称
  • Durable:是否持久化(重启rabbitmq之后,队列是否还存在)
  • Exclusive:是否只被一个客户端连接使用,且当连接关闭后,删除队列
  • AutoDelete :是否自动删除(当最后一个消费者退订后即被删除)
  • Arguments:队列的其他属性参数,有如下可选项:
    (1)x-message-ttl:消息的过期时间,单位:毫秒;
    (2)x-expires:队列过期时间,队列在多长时间未被访问将被删除,单位:毫秒;
    (3)x-max-length:队列最大长度,超过该最大值,则将从队列头部开始删除消息;
    (4)x-max-length-bytes:队列消息内容占用最大空间,受限于内存大小,超过该阈值则从队列头部开始删除消息;
    (5)x-overflow:设置队列溢出行为。这决定了当达到队列的最大长度时消息会发生什么。有效值是drop-head、reject-publish或reject-publish-dlx。仲裁队列类型仅支持drop-head;
    (6)x-dead-letter-exchange:死信交换器名称,过期或被删除(因队列长度超长或因空间超出阈值)的消息可指定发送到该交换器中;
    (7)x-dead-letter-routing-key:死信消息路由键,在消息发送到死信交换器时会使用该路由键,如果不设置,则使用消息的原来的路由键值
    (8)x-single-active-consumer:表示队列是否是单一活动消费者,true时,注册的消费组内只有一个消费者消费消息,其他被忽略,false时消息循环分发给所有消费者(默认false)
    (9)x-max-priority:队列要支持的最大优先级数;如果未设置,队列将不支持消息优先级;
    (10)x-queue-mode(Lazy mode):将队列设置为延迟模式,在磁盘上保留尽可能多的消息,以减少RAM的使用;如果未设置,队列将保留内存缓存以尽可能快地传递消息;
    (11)x-queue-master-locator:在集群模式下设置镜像队列的主节点信息。

队列创建

队列在声明后才能被使用,如果声明的队列已经存在,并且属性完全相同,那么此次声明不会对原有队列产生任何影响,如果声明的队列属性与已存在的队列属性有差异,那么就会抛出{ Channel shutdown: channel error; protocol method: #method<channel.close>reply-code=406, reply-text…}

队列持久化

持久化队列会被存储在磁盘上,当重启rabbitmq的时候,队列依旧存在,没有被持久化的队列称作暂存队列,需注意的是,队列的持久化不意味着队列里的消息也是持久化,需要另外设置;

队列的长度

队列的最大长度可以限制为一定数量的消息或字节,或者两者都可以;如果两者同时设置,都适用,但执行会按两者之间的最小值

在这里插入图片描述
在这里插入图片描述
如果设置了队列长度,并且达到最大值时,其它的消息该何去何从?

当设置了队列长度,并且达到最大值时,RabbitMQ的默认行为是将排在队列最前面的消息丢弃掉或死信消息(如果死信队列设置了最大值,当达到最大值,就会转到死信队列设置转发的另一个队列,当另一个队列再次达到最大值时,就会将排在队列最前面的消息丢弃掉)

如何改变RabbitMQ对队列消息溢出的行为?

RabbitMQ有两种对队列中消息溢出的策略,一种是默认,即抛弃排在队列最前面的消息,另一种是拒绝发布,即丢弃最新发布的消息;

在这里插入图片描述在这里插入图片描述

PS:另外,如果启用了发布者确认,则将通过basic.nack消息通知发布者拒绝。如果一条消息被路由到多个队列并被其中至少一个拒绝,则通道将通过basic.nack通知发布者。该消息仍将发布到所有其他可以排队的队列;

消息的确认

RabbitMQ消息的确认分为两种机制:

1、生产者发送消息的确认
2、消费者接受消息的确认

生产者发送消息的确认

这个是用来确认生产者将消息发送给交换机,交换机传递给队列的过程中,消息是否成功投递,发送确认分为两步:

1、确认是否到达交换器
2、确认是否到达队列

具体实现,需要在yml文件中,设置参数,如下图
在这里插入图片描述
RabbitTemplate(这个大家都会熟悉,就不多介绍)
在这里插入图片描述

消费者接受消息的确认

在实际应用中,可能会发生消费者收到Queue中的消息,在处理消息的时候由于宕机或其它原因,导致消息未被正确处理,而丢失掉(消息被队列删除);为了避免此情况的发生,RabbitMQ提供了两种消息确认模式:

1、自动确认模式:当消息发送到消费者之后,立即删除 ;
2、显示确认模式:当消息发送到消费者之后,等消费者发送一个确认回执,再删除消息;
PS:如果一个消费者在尚未发送确认回执的情况下挂掉了,那么RabbitMQ会将消息重新发送到另一个消费者,如果当时没有可用的消费者,就会一直等待监听此队列的消费者,然后再次尝试发送;

具体实现,需要在yml文件中,设置参数,如下图
在这里插入图片描述
配置SimpleMessageListenerContainer消息监听容器的参数
在这里插入图片描述

PS:监听的队列名称可以设置多个

当设置为手动确认时,要创建一个类,实现ChannelAwareMessageListener接口(我们都知道消息的监听都是通过channel设置的,因此要实现此接口),重写onMessage()方法,见下图
在这里插入图片描述
PS:channel.basicNack与channel.basicReject的区别在于前者的消息能重新入列,后者是直接丢弃

注意:当实现ChannelAwareMessageListener接口,并重写onMessage()方法的类,此类就是一个消费者;当有消息发送到SimpleMessageListenerContainer监听的队列中时,就会执行此方法,并发送消息回执到队列中;

消息的分发

在多个消费者同时订阅同一个Queue中的消息,Queue中的消息会被平摊给多个消费者,也就是给每个消费者分派一个消息,谁先执行完,Queue就会再发送一条消息;
消息的分发数量由prefetch控制,有两种配置方法,见下图在这里插入图片描述在这里插入图片描述
消费者并发数量

默认情况下,RabbitMQ的消费者为单线程串行消费,这意味着此消费者如果因为某些原因,使得队列中的消息发生阻塞,那么后续的消息就无法被消费;RabbitMQ有提供消费者的并发设置,用来解决此问题,有两种配置方式,见下图
在这里插入图片描述
在这里插入图片描述

死信队列

死信,在官网中对应的单词为“Dead Letter”,它是RabbitMQ中的一种消息机制,当你在消费消息时,如果队列里的消息出现以下情况:

1、消息被否认确认,使用channel.basicNack或channel.basicReject,并且requeue属性被设置为false;
2、消息在队列的存活时间超过设置的TTL(过期时间);
3、消息队列的消息数量已超过队列设置的最大长度;
那么该消息将成为“死信”,死信消息会被RabbitMQ进行特殊处理;

死信队列的操作流程

首先,我们来比对下死信队列和普通队列创建的形式,以下是它们的区别:

普通队列和交换机
在这里插入图片描述
死信队列和死信交换机
在这里插入图片描述

对比以上两张图发现,除了死信队列和普通队列的创建略有些不同,其它步骤都是一样的;

PS:
“x-dead-letter-exchange”的值“userOrderExchange”,其实是另一个交换机的名称
“x-dead-letter-routing-key”的值“userOrderRouting”,是发送消息的路由规则,见下图:

死信交换机userOrderExchange和它绑定的queue和routingkey;
在这里插入图片描述
为什么死信队列在创建的时候,要在HashMap集合中设置另一个交换机的名称和routingkey(路由规则)?请看下面死信队列的工作图:

在这里插入图片描述

总结:正常来说,当生产者发送消息时,会根据交换机和路由规则,匹配到指定的死信队列,当发送的消息在死信队列中,不会因为TTL或超过队列最大长度的上限(不会成为死信消息),就会直接发送到消费者,如果发送的消息TTL或超过队列最大长度的上限(成为死信消息),就会把消息按创建死信队列时,设置Routingkey和Exchange,发送到绑定的Queue的上,再发给消费者;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值