背景

常用的消息队列有很多,kafaka、rocketmq、rabbitmq、activemq……等等,都会涉及到消息稳定性,虽然每种mq区别很大,但是对于保证消息不丢失的措施上却大同小异,无非都是从消息流转的途径,进行保障。

措施

从3个层面去分析

不论我们使用消息队列,一定会涉及三个模型,生产者,队列,消费者。

如何保证消息不丢失就要从这三个维度就分析。

如何确保消息队列引入后数据的一致性和稳定性 消息队列防止数据丢失_持久化

1、生产消息

原因:
因网络抖动,服务器宕机等。
解决方案
确保我们的正在发送的消息不被丢失,rabbitmq 给我们提供两种机制,
同步和异步俩种方案
1.1 、同步效率低,运用的事物机制,效率比较低 。(不推荐)
1.2 、异步,异步使用的是异步监听。
      分为俩部分,基于监听机制,
       一、实现 confimCallback ,确保我们的消息发送到交换机
        二、实现 returnCallBack,确保我们的消息从交换机发送到队列。

附图说明:

注:

我们可以发生异常在回调之中记录log,保证我们的消息。

发送失败才会触发rabbitmq回调机制。

如何确保消息队列引入后数据的一致性和稳定性 消息队列防止数据丢失_rabbitmq_02

2、队列消息

原因:
因rabbitmq 服务器宕机导致的问题
解决方案
为了确保rabbitmq上,已经存在未被消费的消息不被丢失。
2.1 、我们可以设置 queue 队列持久化。
2.2 、如果我们使用了交换机,也要记得设置一下我们的 exchange 交换机持久化。

3、消费消息

原因:
因业务处理异常,导致消息未被消费掉,自动ack,导致丢失的问题
解决方案:
3.1、修改默认自动确认机制,改为手动确认。
如何修改手动确认,rabbitmq 提供一个 channel ,
在代码执行完之后调用,channel.basicAck() 方法,里面会传俩个值,
一个是消息投发的状态,一个是布尔。确认我们的消息被消费掉。

3.2、设置重试机制,并设定重试时间间隔。这个主要是为了防止因网络抖动的问题。

3.3、对重试失败的消息,放入到死信队列,并记录到日志库里面。

总结

其实上面三个环节都可以一定保障消息的可靠性,但不能完全解决消息的不丢失。

在生产消息时,假设我们的消息发送到交换机也被分发到了消息队列里面,此时还未消费。
但此时可能还未从内存中刷到磁盘中,就突然宕机了。如果想要绝对保证消息的不丢失,
需要在生产者发送消息到broker之前,备份一下消息存到redis或者db中,直到消息被消费
再去把消息从redis或者db中删除,方可绝对保障消息持久化不丢失。
俗话说,别把鸡蛋放在一个篮子里。