1、如何保证RabbitMQ消息不丢失
以下情况消息会丢失
实现消息的高可用性,具体措施包括:
1.1、开启生产者确认机制
确保消息能被送达队列,如有错误则记录日志并修复数据。
消息失败之后处理方式:
回调方法即时重发
记录日志
保存到数据库然后定时重发,成功发送后即刻删除表中的数据
1.2、启用持久化功能
保证消息在未消费前不会在队列中丢失,需要对交换机、队列和消息本身都进行持久化。
MQ默认是内存存储消息,开启持久化功能可以确保缓存在MQ中的消息不丢失。
1.交换机持久化:
2.队列持久化
3.消息持久化,SpringAMQP中的的消息默认是持久的,可以通过MessageProperties中的DeliveryMode来指定
1.3、对消费者开启自动确认机制
RabbitMQ支持消费者确认机制,即:消费者处理消息后可以向MQ发送ack回执,MQ收到ack回执后才会删除该消息。而SpringAMQP则允许配置三种确认模式:
manual:手动ack,需要在业务代码结束后,调用api发送ack。
auto: 自动ack,由spring监测listener代码是否出现异常,没有异常则返回ack;抛出异常则返回nack
none:关闭ack,MQ假定消费者获取消息后会成功处理,因此消息投递后立即被删除
我们可以利用Spring的retry机制,在消费者出现异常时利用本地重试,设置重试次数,当次数达到了以后,如果消息依然失败,将消息投递到异常交换机,交由人工处理
2、RabbitMQ消息重复消费问题
解决方案:
每条消息设置一个唯一的标识id
幂等方案:【分布式锁、数据库锁 (悲观锁、乐观锁)
给消息设置一个唯一id,检索数据在数据库中是否存在
3、RabbitMQ的死信交换机?
3.1 什么是死信交换机
当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter):
消费者使用basic.reject或 basic.nack声明消费失败,并且消息的requeue参数设置为false
消息是一个过期消息,超时无人消费
要投递的队列消息堆积满了,最早的消息可能成为死信
如果该队列配置了dead-letter-exchange属性,指定了一个交换机,那么队列中的死信就会投递到这个交换机中,而这个交换机称为死信交换机(Dead Letter Exchange,简称DLX)。
3.2、TTL
TTL,也就是Time-To-Live。如果一个队列中的消息TTL结束仍未消费,则会变为死信,ttl超时分为两种情况:
消息所在的队列设置了存活时间
消息本身设置了存活时间
3.3 延时队列
延迟队列=死信队列+TTL
延迟队列:进入队列的消息会被延迟消费的队列
场景:超时订单、限时优惠、定时发布
延迟队列还可以使用延迟插件
参考 4.2 DelayExchange插件
4、RabbitMQ如果有100万消息堆积在MQ , 如何解决(消息堆积怎么解决)
当生产者发送消息的速度超过了消费者处理消息的速度,就会导致队列中的消息堆积,直到队列存储消息达到上限。之后发送的消息就会成为死信,可能会被丢弃,这就是消息堆积问题
解决消息堆积有三种种思路:
增加更多消费者,提高消费速度
在消费者内开启线程池加快消息处理速度
扩大队列容积,提高堆积上限
惰性队列
惰性队列的特征如下:
接收到消息后直接存入磁盘而非内存
消费者要消费消息时才会从磁盘中读取并加载到内存
支持数百万条的消息存储