RabbitMQ高级(消息可靠性,死信,延迟队列,消息堆积)

1.如何保证消息的可靠性

首先需要明白生产者和消费者之间是如何通过RabbitMQ进行通信的
生产者发送消息到交换机中,交换机发送给对应的队列,再由消费者进行消费
这中间有几个环节都会有可能会消息丢失,rabbitMQ其实给我们提供好了对应的解决方案

1.首先是生产者这边
a. 生产者发送消息给交换机的时候,有可能会产生消息丢失的问题,我们可以用public-confirm机制防止消息丢失,当消息成功发送到交换机中的时候,就会返回ack,失败的时候会返回nack.
b. 由交换机发送消息到队列中的时候,可以使用publish-return机制防止消息丢失,失败的时候会返回ack,以及失败的原因,应答码,交换机,路由键,消息

2.RabbitMQ默认,消息,交换机,队列都是非持久化的,因此重启mq,这些东西的数据都会丢失,因此我们需要设置持久化,不过SpringAMQP对其进行封装了之后,默认都是持久化的

3.RabbitMQ是阅后即焚机制,RabbitMQ确认消息被消费者消费后会立刻删除。
而RabbitMQ是通过消费者回执来确认消费者是否成功处理消息的:消费者获取消息后,应该向RabbitMQ发送ACK回执,表明自己已经处理消息。
而SpringAMQP则允许配置三种确认模式:
a. manual:手动ack,需要在业务代码结束后,调用api发送ack。
b. auto:自动ack,由spring监测listener代码是否出现异常,没有异常则返回ack;抛出异常则返回nack
c. none:关闭ack,MQ假定消费者获取消息后会成功处理,因此消息投递后立即被删除
由此可知:
d. none模式下,消息投递是不可靠的,可能丢失
e. auto模式类似事务机制,出现异常时返回nack,消息回滚到mq;没有异常,返回ack
f. manual:自己根据业务情况,判断什么时候该ack
一般,我们都是使用默认的auto即可
但是由此又会出现一个问题,就是如果确认的时候一直有异常,那么消息就会一直回滚到mq这样就会产生死循环问题,因此消费失败的时候,我们可以利用Spring的retry机制,在消费者出现异常时利用本地重试,而不是无限制的requeue到mq队列。我们要去定义失败重试机制,我们可以设置重试次数,当达到这个次数的时候,Spring会返回ack,消息会被丢弃,这显然不是我们所期望的,因此我们需要定义失败策略.
在开启重试模式后,重试次数耗尽,如果消息依然失败,则需要有MessageRecovery接口来处理,它包含三种不同的实现:
● RejectAndDontRequeueRecoverer:重试耗尽后,直接reject,丢弃消息。默认就是这种方式
● ImmediateRequeueMessageRecoverer:重试耗尽后,返回nack,消息重新入队
● RepublishMessageRecoverer:重试耗尽后,将失败消息投递到指定的交换机
比较优雅的一种处理方案是RepublishMessageRecoverer,失败后将消息投递到一个指定的,专门存放异常消息的队列,后续由人工集中处理。

2.有哪些情况会产生死信消息

什么是死信?
当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter):
● 消费者使用basic.reject或 basic.nack声明消费失败,并且消息的requeue参数设置为false
● 消息是一个过期消息,超时无人消费
● 要投递的队列消息满了,无法投递

如果这个包含死信的队列配置了dead-letter-exchange属性,指定了一个交换机,那么队列中的死信就会投递到这个交换机中,而这个交换机称为死信交换机(Dead Letter Exchange,检查DLX)。
在失败重试策略中,默认的RejectAndDontRequeueRecoverer会在本地重试次数耗尽后,发送reject给RabbitMQ,消息变成死信,被丢弃。
我们可以给simple.queue添加一个死信交换机,给死信交换机绑定一个队列。这样消息变成死信后也不会丢弃,而是最终投递到死信交换机,路由到与死信交换机绑定的队列。

3.如何实现延迟队列

1.利用TTL结合死信交换机,我们实现了消息发出后,消费者延迟收到消息的效果。这种消息模式就称为延迟队列(Delay Queue)模式。
延迟队列的使用场景包括:
● 延迟发送短信
● 用户下单,如果用户在15 分钟内未支付,则自动取消
● 预约工作会议,20分钟后自动通知所有参会人员
2.DelayExchange需要将一个交换机声明为delayed类型。当我们发送消息到delayExchange时,流程如下:
● 接收消息
● 判断消息是否具备x-delay属性
● 如果有x-delay属性,说明是延迟消息,持久化到硬盘,读取x-delay值,作为延迟时间
● 返回routing not found结果给消息发送者
● x-delay时间到期后,重新投递消息到指定队列

4.什么事消息堆积?怎么解决?

当生产者发送消息的速度超过了消费者处理消息的速度,就会导致队列中的消息堆积,直到队列存储消息达到上限。之后发送的消息就会成为死信,可能会被丢弃,这就是消息堆积问题。
解决消息堆积有两种思路:
● 增加更多消费者,提高消费速度。也就是我们之前说的work queue模式
● 扩大队列容积,提高堆积上限
要提升队列容积,把消息保存在内存中显然是不行的。
● 队列过长的话会占用系统较多内存,RabbitMQ为了释放内存,会将队列消息转储到硬盘,称为 page out 。 如果队列很长,Page out 操作会消耗较长时间,且page out 过程中队列不能处理消息。因此会出现间歇性的暂停状态、并发时出现波浪性的忽高忽低现象
● 队列过长同时会加长RabbitMQ重启时间,因为启动时候需要重建索引。
● 队列过长还会导致集群之间节点同步消息时间变长
从RabbitMQ的3.6.0版本开始,就增加了Lazy Queues的概念,也就是惰性队列。惰性队列的特征如下:
● 接收到消息后直接存入磁盘而非内存
● 消费者要消费消息时才会从磁盘中读取并加载到内存
● 支持数百万条的消息存储

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值