1.生产者存放消息的过程中丢失消息
解决办法:
1)事务机制:(同步方式,不推荐)
对于RabbitMQ来说,生产者发送数据之前开启RabbitMQ的事务机制 channel.txselect
,如果消息没有进队列,则生产者受到异常报错,并进行回滚channel.txRollback
,然后重试发送消息。如果收到了消息,则可以提交事务channel.txCommit
。这是同步操作,会影响性能。
2)异步机制:confirm
模式来解决同步机制的性能问题。每次生产者发送的消息都会分配一个唯一的id,如果写入到了RabbitMQ队列中,则RabbitMQ会回传一个ack
消息,说明这个消息接收成功。如果RabbitMQ没能处理这个消息,则回调nack
接口。说明需要重试发送消息。
也可以自定义超时时间 + 消息 id 来实现超时等待后重试机制。但可能出现的问题是调用ack接口时失败了,所以会出现消息被发送两次的问题,这个时候就需要保证消费者消费消息的幂等性。
事务模式和confirm模式的区别:
- 事务机制是同步的,提交事务后悔被阻塞直到提交事务完成后。
- confirm 模式异步接收通知,但可能接收不到通知。需要考虑接收不到通知的场景。
2.消息队列消息丢失
解决办法:
- 1,创建
Queue
时,将其设置为持久化 - 2,发送消息的时候将消息的
deliveryMode
设置为2
(将消息持久化 1:非持久化,2:持久化) - 3,开启生产者 confirm`模式,可以重试发送消息。
3.消费者丢失消息
解决办法:
- 关闭RabbitMQ的自动
ack
,每次生产者将消息写入消息队列后,就自动回传一个ack
给生产者。 - 消费者处理完消息再主动
ack
,告诉消息队列我处理完了。
4.总结
- 1.开启生产者消息手动确认机制
- 2.开启消息持久化,队列持久化,交换机持久化(默认开启)
- 3.开启消费者消息手动确认机制
遗留问题:那这种主动 ack
有什么漏洞了?如果 主动 ack
的时候挂了,怎么办?
来这儿——消息中间件MQ场景常见问题(消息丢失,重复消费,垃圾消息,延时消费)