消息什么情况下会丢失?配合mandatory参数或备份交换器来提高程序的健壮性
预估队列的使用情况?
在后期运行过程中超过预定的阈值,可以根据实际情况对当前集群进行扩容或者将相应的队列迁移到其他集群。
消费消息?
推模式,拉模式
保证消息的可靠性?
RabbitMQ 提供了消息确认机制( message acknowledgement)。 消费者在订阅队列时,可以指定 autoAck 参数,当 autoAck 等于 false 时, RabbitMQ 会等待消费者显式地回复确认信号后才从内存(或者磁盘)中移去消息(实质上
是先打上删除标记,之后再删除)。当 autoAck 等于 true 时, RabbitMQ 会自动把发送出去的 消息置为确认,然后从内存(或者磁盘)中删除,而不管消费者是否真正地消费到了这些消息。
在ack为false的情况下,消费者获取消息迟迟没有发送消费者确认消息的信号或者消费者断开,怎么办?
当 autoAck 参数置为 false,对于 RabbitMQ 服务端而言,队列中的消息分成了两个部分: 一部分是等待投递给消费者的消息:一部分是己经投递给消费者,但是还没有收到消费者确认信号的消息。 如果 RabbitMQ 一直没有收到消费者的确认信号,并且消费此消息的消费者己经 断开连接,则 RabbitMQ 会安排该消息重新进入队列,等待投递给下一个消费者,当然也有可 能还是原来的那个消费者。RabbitMQ 不会为未确认的消息设置过期时间,它判断此消息是否需要重新投递给消费者的唯一依据是消费该消息的消费者连接是否己经断开,这么设计的原因是 RabbitMQ 允许消费者 消费一条消息的时间可以很久很久。
在消费者接收到消息后,如果想明确拒绝当前的消息而不是确认,那么应该怎么做呢?
RabbitMQ 在 2.0.0 版本开始引入了 Basic .Reject 这个命令,消费者客户端可以调用与其对 应的 channel.basicReject 方法来告诉 RabbitMQ 拒绝这个消息。
//Channel 类中的 basicReject 方法定义如下:
//其中 deliveryTag 可以看作消息的编号 ,它是一个 64 位的长整型值,最大值是 9223372036854775807。如果 //requeue 参数设置为 true,则 RabbitMQ 会重新将这条消息存入 队列,以便可以发送给下一个订阅的消费者;如果 //requeue 参数设置为 false,则 RabbitMQ 立即会把消息从队列中移除,而不会把它发送给新的消费者。
void basicReject(long deliveryTag, boolean requeue) throws IOException
注意:
Basic.Reject 命令一次只能拒绝一条消息 ,如果想要批量拒绝消息 ,则可以使用 Basic.Nack 这个命令
//消费者客户端可以调用 channel.basicNack 方法来实现,方法定 义如下:
//其中 deliveryTag 和 requeue 的含义可以参考 basicReject 方法。 multiple 参数
//设置为 false 则表示拒绝编号为 deliveryT坷的这一条消息,这时候 basicNack 和 basicReject 方法一样; //multiple 参数设置为 true 则表示拒绝 deliveryTag 编号之前所 有未被当前消费者确认的消息。
void basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException
注意:
将 channel.basicReject 或者 channel.basicNack 中的 requeue 设直为 false,可以启用”死信队列”的功能。死信队列可以通过检测被拒绝或者未送达的消息来追踪问题
请求RabbitMQ重新发送还未被确认的消息?
//Basic.Recover 具备可重入队列的特性
Basic.RecoverOk basicRecover() throws IOException;
Basic.RecoverOk basicRecover(boolean requeue) throws IOException;
channel.basicRecover 方法用来请求 RabbitMQ 重新发送还未被确认的消息。 如果 requeue 参数设置为 true,则未被确认的消息会被重新加入到队列中,这样对于同一条消息 来说,可能会被分配给与之前不同的消费者。如果 requeue 参数设置为 false,那么同一条消 息会被分配给与之前相同的消费者。默认情况下,如果不设置 requeue 这个参数,相当于
channel.basicRecover(true) ,即 requeue 默认为 true
交换器无法根据自身的类型和路由键找到一个符合条件 的队列
当 mandatory 参数设为 true 时,交换器无法根据自身的类型和路由键找到一个符合条件 的队列,那么 RabbitMQ 会调用 Basic.Return 命令将消息返回给生产者。当 mandatory 参 数设置为 false 时,出现上述情形,则消息直接被丢弃
生产者如何获取到没有被正确路由到合适队列的消息呢?
可以通过调用channel.addReturnListener来添加ReturnListener监听器实现。RabbitMQ 会通过 Basic . Return 返回 “mandatory test” 这条消息,之后生产者客户端通过 ReturnListener 监昕到了这个事 件,上面代码的最后输出应该是”Basic.Retum 返回的结果是: mandatory test”
mandatory和immediate参数的区别
mandatory 参数告诉服务器至少将该消息路由到一个队列中, 否则将消息返 回给生产者。 immediate 参数告诉服务器, 如果该消息关联的队列上有消费者, 则立刻投递: 如果所有匹配的队列上都没有消费者,则直接将消息返还给生产者, 不用将消息存入队列而等 待消费者了。
未被路由到的消息应该怎么处理?
备份交换器需要注意?
怎么为消息设置过期时间TTL?
对过期消息处理?
怎么设置队列的过期时间?
什么是死信队列?
什么是延迟队列?
延迟队列存储的对象是对应的延迟消息,所谓“延迟消息”是指当消息被发送后,并不想让消费者立刻拿到消息,而是等待特定时间后,消费者才能拿到这个消息进行消费
延迟队列应用场景?
持久化?
交换器的持久化
交换器的持久化是通过在声明交换器时将 durable 参数置为 true 实现的,如果交换器不设置持久化,那么在 RabbitMQ 服务重启之后,相关的交换器元数据会丢失, 不过消息不会丢失,只是不能将消息发送到这个交换器中了。对一个长期使用的交换器来说,建议将其置为持久化的。
队列的持久化
队列的持久化是通过在声明队列时将 durable 参数置为 true 实现的,如果队列不设置持久化,那么在 RabbitMQ 服务重启之后,相关队列的元数据会丢失,此时数据也会丢失。
消息的持久化
通过将消息的投递模式 (BasicProperties 中的 deliveryMode 属性)设置为 2 即可实现消息的持久化。
在这段时间内 RabbitMQ 服务节点发生了岩机、重启等异常情况,消息保存还没来得及落盘,那么这些消息将RabbitMQ 实战指南会丢失。这个问题怎么解决呢?
可以引入 RabbitMQ 的镜像队列机制,相当于配置了副本,如果主节点 Cmaster) 在此特殊时间内挂掉,可以自动切换到从节点 Cslave ), 这样有效地保证了高可用性
当消息的生产者将消息发送出去之后,消息到底有没有正确地到达服务器呢?
通过事务机制实现,比较消耗性能
通过发送方确认机制实现
消费端对消息的处理?
消费端存在的问题?
消息分发
同一个队列拥有多个消费者,会采用轮询的方式分发消息给消费者,若其中有的消费者任务重,有的消费者很快处理完消息,导致进程空闲,这样对导致整体应用吞吐量下降,为了解决上面的问题,用到channel.basicQos 方法允许限制信道上的消费者所能保持的最大未确认消息的数量。Basic.Qos 的使用对于拉模式的消费方式无效.
举例如下:
在订阅消费队列之前,消费端程序调用了 channel.basicQos(5) ,之后订 阅了某个队列进行消费。 RabbitMQ 会保存一个消费者的列表,每发送一条消息都会为对应的消费者计数,如果达到了所设定的上限,那么 RabbitMQ 就不会向这个消费者再发送任何消息。 直到消费者确认了某条消息之后 , RabbitMQ将相应的计数减1,之后消费者可以继续接收消息, 直到再次到达计数上限。这种机制可以类比于 TCP!IP中的”滑动窗口”。
消息顺序性
可以考虑在消息体内添加全局有序标识来实现
弃用QueueingConsumer,Spring提供的RabbitMQ采用的是DefaultConsume
消息传输保障?
提高数据可靠性途径?